From ba33576f51f79b28348f752e220c23931f0ac7ac Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Thu, 5 Dec 2019 19:05:21 +1100 Subject: [PATCH] File restructuring --- controllers/application_controller.rb | 27 ++ controllers/extra_locales_controller.rb | 20 ++ controllers/invites_controller.rb | 22 ++ lib/wizard/choice.rb | 17 ++ lib/wizard/field.rb | 37 +++ lib/wizard/step.rb | 7 + plugin.rb | 353 +++--------------------- serializers/site_serializer.rb | 22 ++ serializers/wizard_field_serializer.rb | 45 +++ serializers/wizard_serializer.rb | 99 +++++++ serializers/wizard_step_serializer.rb | 25 ++ 11 files changed, 359 insertions(+), 315 deletions(-) create mode 100644 controllers/application_controller.rb create mode 100644 controllers/extra_locales_controller.rb create mode 100644 controllers/invites_controller.rb create mode 100644 lib/wizard/choice.rb create mode 100644 lib/wizard/field.rb create mode 100644 lib/wizard/step.rb create mode 100644 serializers/site_serializer.rb create mode 100644 serializers/wizard_field_serializer.rb create mode 100644 serializers/wizard_serializer.rb create mode 100644 serializers/wizard_step_serializer.rb diff --git a/controllers/application_controller.rb b/controllers/application_controller.rb new file mode 100644 index 00000000..5e6358d2 --- /dev/null +++ b/controllers/application_controller.rb @@ -0,0 +1,27 @@ +module ApplicationControllerCWExtension + extend ActiveSupport::Concern + + included do + before_action :redirect_to_wizard_if_required, if: :current_user + end + + def redirect_to_wizard_if_required + wizard_id = current_user.custom_fields['redirect_to_wizard'] + @excluded_routes ||= SiteSetting.wizard_redirect_exclude_paths.split('|') + ['/w/'] + url = request.referer || request.original_url + + if request.format === 'text/html' && !@excluded_routes.any? {|str| /#{str}/ =~ url} && wizard_id + if request.referer !~ /\/w\// && request.referer !~ /\/invites\// + CustomWizard::Wizard.set_submission_redirect(current_user, wizard_id, request.referer) + end + + if CustomWizard::Wizard.exists?(wizard_id) + redirect_to "/w/#{wizard_id.dasherize}" + end + end + end +end + +class ApplicationController + prepend ApplicationControllerCWExtension if SiteSetting.custom_wizard_enabled +end \ No newline at end of file diff --git a/controllers/extra_locales_controller.rb b/controllers/extra_locales_controller.rb new file mode 100644 index 00000000..e1da1803 --- /dev/null +++ b/controllers/extra_locales_controller.rb @@ -0,0 +1,20 @@ +module CustomWizardExtraLocalesController + def show + if request.referer && URI(request.referer).path.include?('/w/') + bundle = params[:bundle] + + if params[:v]&.size == 32 + hash = ExtraLocalesController.bundle_js_hash(bundle) + immutable_for(1.year) if hash == params[:v] + end + + render plain: ExtraLocalesController.bundle_js(bundle), content_type: "application/javascript" + else + super + end + end +end + +class ExtraLocalesController + prepend CustomWizardExtraLocalesController if SiteSetting.custom_wizard_enabled +end \ No newline at end of file diff --git a/controllers/invites_controller.rb b/controllers/invites_controller.rb new file mode 100644 index 00000000..760100f2 --- /dev/null +++ b/controllers/invites_controller.rb @@ -0,0 +1,22 @@ +module InvitesControllerCustomWizard + def path(url) + if Wizard.user_requires_completion?(@user) + wizard_id = @user.custom_fields['custom_wizard_redirect'] + + if wizard_id && url != '/' + CustomWizard::Wizard.set_submission_redirect(@user, wizard_id, url) + url = "/w/#{wizard_id.dasherize}" + end + end + super(url) + end + + private def post_process_invite(user) + super(user) + @user = user + end +end + +class InvitesController + prepend InvitesControllerCustomWizard if SiteSetting.custom_wizard_enabled +end \ No newline at end of file diff --git a/lib/wizard/choice.rb b/lib/wizard/choice.rb new file mode 100644 index 00000000..f0aa6bf3 --- /dev/null +++ b/lib/wizard/choice.rb @@ -0,0 +1,17 @@ +module CustomWizardChoiceExtension + def initialize(id, opts) + @id = id + @opts = opts + @data = opts[:data] + @extra_label = opts[:extra_label] + @icon = opts[:icon] + end + + def label + @label ||= PrettyText.cook(@opts[:label]) + end +end + +class Wizard::Choice + prepend CustomWizardChoiceExtension if SiteSetting.custom_wizard_enabled +end \ No newline at end of file diff --git a/lib/wizard/field.rb b/lib/wizard/field.rb new file mode 100644 index 00000000..038fdbbc --- /dev/null +++ b/lib/wizard/field.rb @@ -0,0 +1,37 @@ +module CustomWizardFieldExtension + attr_reader :label, + :description, + :image, + :key, + :min_length, + :file_types, + :limit, + :property + + attr_accessor :dropdown_none + + def initialize(attrs) + @attrs = attrs || {} + @id = attrs[:id] + @type = attrs[:type] + @required = !!attrs[:required] + @description = attrs[:description] + @image = attrs[:image] + @key = attrs[:key] + @min_length = attrs[:min_length] + @value = attrs[:value] + @choices = [] + @dropdown_none = attrs[:dropdown_none] + @file_types = attrs[:file_types] + @limit = attrs[:limit] + @property = attrs[:property] + end + + def label + @label ||= PrettyText.cook(@attrs[:label]) + end +end + +class Wizard::Field + prepend CustomWizardFieldExtension if SiteSetting.custom_wizard_enabled +end \ No newline at end of file diff --git a/lib/wizard/step.rb b/lib/wizard/step.rb new file mode 100644 index 00000000..b58bc837 --- /dev/null +++ b/lib/wizard/step.rb @@ -0,0 +1,7 @@ +module CustomWizardStepExtension + attr_accessor :title, :description, :key, :permitted, :permitted_message +end + +class Wizard::Step + prepend CustomWizardStepExtension if SiteSetting.custom_wizard_enabled +end \ No newline at end of file diff --git a/plugin.rb b/plugin.rb index a02013e0..e7168536 100644 --- a/plugin.rb +++ b/plugin.rb @@ -11,8 +11,9 @@ register_asset 'lib/jquery.timepicker.scss' enabled_site_setting :custom_wizard_enabled config = Rails.application.config -config.assets.paths << Rails.root.join('plugins', 'discourse-custom-wizard', 'assets', 'javascripts') -config.assets.paths << Rails.root.join('plugins', 'discourse-custom-wizard', 'assets', 'stylesheets', 'wizard') +plugin_asset_path = "#{Rails.root}/plugins/discourse-custom-wizard/assets" +config.assets.paths << "#{plugin_asset_path}/javascripts" +config.assets.paths << "#{plugin_asset_path}/stylesheets/wizard" if Rails.env.production? config.assets.precompile += %w{ @@ -44,6 +45,9 @@ after_initialize do '../controllers/custom_wizard/admin.rb', '../controllers/custom_wizard/transfer.rb', '../controllers/custom_wizard/api.rb', + '../controllers/application_controller.rb', + '../controllers/extra_locales_controller.rb', + '../controllers/invites_controller.rb', '../jobs/clear_after_time_wizard.rb', '../jobs/refresh_api_access_token.rb', '../jobs/set_after_time_wizard.rb', @@ -57,342 +61,61 @@ after_initialize do '../lib/custom_wizard/api/authorization.rb', '../lib/custom_wizard/api/endpoint.rb', '../lib/custom_wizard/api/log_entry.rb', + '../lib/wizard/choice.rb', + '../lib/wizard/field.rb', + '../lib/wizard/step.rb', '../serializers/custom_wizard/api_serializer.rb', '../serializers/custom_wizard/basic_api_serializer.rb', '../serializers/custom_wizard/api/authorization_serializer.rb', '../serializers/custom_wizard/api/basic_endpoint_serializer.rb', '../serializers/custom_wizard/api/endpoint_serializer.rb', - '../serializers/custom_wizard/api/log_serializer.rb' + '../serializers/custom_wizard/api/log_serializer.rb', + '../serializers/site_serializer.rb', + '../serializers/wizard_serializer.rb', + '../serializers/wizard_step_serializer.rb', + '../serializers/wizard_field_serializer.rb' ].each do |path| load File.expand_path(path, __FILE__) end - ::Wizard.class_eval do - def self.user_requires_completion?(user) - wizard_result = self.new(user).requires_completion? - return wizard_result if wizard_result + add_class_method(:wizard, :user_requires_completion?) do |user| + wizard_result = self.new(user).requires_completion? + return wizard_result if wizard_result - custom_redirect = false + custom_redirect = false - if user && user.first_seen_at.blank? && wizard_id = CustomWizard::Wizard.after_signup - wizard = CustomWizard::Wizard.create(user, wizard_id) + if user && + user.first_seen_at.blank? && + wizard_id = CustomWizard::Wizard.after_signup + + wizard = CustomWizard::Wizard.create(user, wizard_id) - if !wizard.completed? && wizard.permitted? - custom_redirect = true - CustomWizard::Wizard.set_wizard_redirect(user, wizard_id) - end - end - - !!custom_redirect - end - end - - ::Wizard::Field.class_eval do - attr_reader :label, :description, :image, :key, :min_length, :file_types, :limit, :property - attr_accessor :dropdown_none - - def initialize(attrs) - @attrs = attrs || {} - @id = attrs[:id] - @type = attrs[:type] - @required = !!attrs[:required] - @description = attrs[:description] - @image = attrs[:image] - @key = attrs[:key] - @min_length = attrs[:min_length] - @value = attrs[:value] - @choices = [] - @dropdown_none = attrs[:dropdown_none] - @file_types = attrs[:file_types] - @limit = attrs[:limit] - @property = attrs[:property] - end - - def label - @label ||= PrettyText.cook(@attrs[:label]) - end - end - - ::Wizard::Choice.class_eval do - def initialize(id, opts) - @id = id - @opts = opts - @data = opts[:data] - @extra_label = opts[:extra_label] - @icon = opts[:icon] - end - - def label - @label ||= PrettyText.cook(@opts[:label]) - end - end - - class ::Wizard::Step - attr_accessor :title, :description, :key, :permitted, :permitted_message - end - - ::WizardSerializer.class_eval do - attributes :id, - :name, - :background, - :completed, - :required, - :min_trust, - :permitted, - :user, - :categories, - :uncategorized_category_id - - def id - object.id - end - - def include_id? - object.respond_to?(:id) - end - - def name - object.name - end - - def include_name? - object.respond_to?(:name) - end - - def background - object.background - end - - def include_background? - object.respond_to?(:background) - end - - def completed - object.completed? - end - - def include_completed? - object.completed? && - (!object.respond_to?(:multiple_submissions) || !object.multiple_submissions) && - !scope.is_admin? - end - - def min_trust - object.min_trust - end - - def include_min_trust? - object.respond_to?(:min_trust) - end - - def permitted - object.permitted? - end - - def include_permitted? - object.respond_to?(:permitted?) - end - - def include_start? - object.start && include_steps? - end - - def include_steps? - !include_completed? - end - - def required - object.required - end - - def include_required? - object.respond_to?(:required) - end - - def user - object.user - end - - def categories - begin - site = ::Site.new(scope) - ::ActiveModel::ArraySerializer.new(site.categories, each_serializer: BasicCategorySerializer) - rescue => e - puts "HERE IS THE ERROR: #{e.inspect}" - end - end - - def uncategorized_category_id - SiteSetting.uncategorized_category_id - end - end - - ::WizardStepSerializer.class_eval do - attributes :permitted, :permitted_message - - def title - return PrettyText.cook(object.title) if object.title - PrettyText.cook(I18n.t("#{object.key || i18n_key}.title", default: '')) - end - - def description - return object.description if object.description - PrettyText.cook(I18n.t("#{object.key || i18n_key}.description", default: '', base_url: Discourse.base_url)) - end - - def permitted - object.permitted - end - - def permitted_message - object.permitted_message - end - end - - ::WizardFieldSerializer.class_eval do - attributes :dropdown_none, :image, :file_types, :limit, :property - - def label - return object.label if object.label.present? - I18n.t("#{object.key || i18n_key}.label", default: '') - end - - def description - return object.description if object.description.present? - I18n.t("#{object.key || i18n_key}.description", default: '', base_url: Discourse.base_url) - end - - def image - object.image - end - - def include_image? - object.image.present? - end - - def placeholder - I18n.t("#{object.key || i18n_key}.placeholder", default: '') - end - - def dropdown_none - object.dropdown_none - end - - def file_types - object.file_types - end - - def limit - object.limit - end - - def property - object.property - end - end - - ::UsersController.class_eval do - def wizard_path - if custom_wizard_redirect = current_user.custom_fields['redirect_to_wizard'] - "#{Discourse.base_url}/w/#{custom_wizard_redirect.dasherize}" - else - "#{Discourse.base_url}/wizard" - end - end - end - - module InvitesControllerCustomWizard - def path(url) - if Wizard.user_requires_completion?(@user) - wizard_id = @user.custom_fields['custom_wizard_redirect'] - - if wizard_id && url != '/' - CustomWizard::Wizard.set_submission_redirect(@user, wizard_id, url) - url = "/w/#{wizard_id.dasherize}" - end - end - super(url) - end - - private def post_process_invite(user) - super(user) - @user = user - end - end - - require_dependency 'invites_controller' - class ::InvitesController - prepend InvitesControllerCustomWizard - end - - require_dependency 'application_controller' - class ::ApplicationController - before_action :redirect_to_wizard_if_required, if: :current_user - - def redirect_to_wizard_if_required - wizard_id = current_user.custom_fields['redirect_to_wizard'] - @excluded_routes ||= SiteSetting.wizard_redirect_exclude_paths.split('|') + ['/w/'] - url = request.referer || request.original_url - - if request.format === 'text/html' && !@excluded_routes.any? {|str| /#{str}/ =~ url} && wizard_id - if request.referer !~ /\/w\// && request.referer !~ /\/invites\// - CustomWizard::Wizard.set_submission_redirect(current_user, wizard_id, request.referer) - end - - if CustomWizard::Wizard.exists?(wizard_id) - redirect_to "/w/#{wizard_id.dasherize}" - end - end - end - end - - add_to_serializer(:current_user, :redirect_to_wizard) {object.custom_fields['redirect_to_wizard']} - - ## TODO limit this to the first admin - SiteSerializer.class_eval do - attributes :complete_custom_wizard - - def include_wizard_required? - scope.is_admin? && Wizard.new(scope.user).requires_completion? - end - - def complete_custom_wizard - if scope.user && requires_completion = CustomWizard::Wizard.prompt_completion(scope.user) - requires_completion.map {|w| {name: w[:name], url: "/w/#{w[:id]}"}} + if !wizard.completed? && wizard.permitted? + custom_redirect = true + CustomWizard::Wizard.set_wizard_redirect(user, wizard_id) end end - def include_complete_custom_wizard? - complete_custom_wizard.present? + !!custom_redirect + end + + add_to_class(:users_controller, :wizard_path) do + if custom_wizard_redirect = current_user.custom_fields['redirect_to_wizard'] + "#{Discourse.base_url}/w/#{custom_wizard_redirect.dasherize}" + else + "#{Discourse.base_url}/wizard" end end + add_to_serializer(:current_user, :redirect_to_wizard) do + object.custom_fields['redirect_to_wizard'] + end + DiscourseEvent.on(:user_approved) do |user| if wizard_id = CustomWizard::Wizard.after_signup CustomWizard::Wizard.set_wizard_redirect(user, wizard_id) end end - - module CustomWizardExtraLocalesController - def show - if request.referer && URI(request.referer).path.include?('/w/') - bundle = params[:bundle] - - if params[:v]&.size == 32 - hash = ExtraLocalesController.bundle_js_hash(bundle) - immutable_for(1.year) if hash == params[:v] - end - - render plain: ExtraLocalesController.bundle_js(bundle), content_type: "application/javascript" - else - super - end - end - end - - class ::ExtraLocalesController - prepend CustomWizardExtraLocalesController - end DiscourseEvent.trigger(:custom_wizard_ready) end diff --git a/serializers/site_serializer.rb b/serializers/site_serializer.rb new file mode 100644 index 00000000..21b996f6 --- /dev/null +++ b/serializers/site_serializer.rb @@ -0,0 +1,22 @@ +## TODO limit this to the first admin +module SiteSerializerCWX + attributes :complete_custom_wizard + + def include_wizard_required? + scope.is_admin? && Wizard.new(scope.user).requires_completion? + end + + def complete_custom_wizard + if scope.user && requires_completion = CustomWizard::Wizard.prompt_completion(scope.user) + requires_completion.map {|w| {name: w[:name], url: "/w/#{w[:id]}"}} + end + end + + def include_complete_custom_wizard? + complete_custom_wizard.present? + end +end + +class SiteSerializer + prepend SiteSerializerCWX if SiteSetting.custom_wizard_enabled +end \ No newline at end of file diff --git a/serializers/wizard_field_serializer.rb b/serializers/wizard_field_serializer.rb new file mode 100644 index 00000000..1749fb89 --- /dev/null +++ b/serializers/wizard_field_serializer.rb @@ -0,0 +1,45 @@ +module CustomWizardWizardFieldSerializerExtension + attributes :dropdown_none, :image, :file_types, :limit, :property + + def label + return object.label if object.label.present? + I18n.t("#{object.key || i18n_key}.label", default: '') + end + + def description + return object.description if object.description.present? + I18n.t("#{object.key || i18n_key}.description", default: '', base_url: Discourse.base_url) + end + + def image + object.image + end + + def include_image? + object.image.present? + end + + def placeholder + I18n.t("#{object.key || i18n_key}.placeholder", default: '') + end + + def dropdown_none + object.dropdown_none + end + + def file_types + object.file_types + end + + def limit + object.limit + end + + def property + object.property + end +end + +class WizardFieldSerializer + prepend CustomWizardWizardFieldSerializerExtension if SiteSetting.custom_wizard_enabled +end \ No newline at end of file diff --git a/serializers/wizard_serializer.rb b/serializers/wizard_serializer.rb new file mode 100644 index 00000000..18659417 --- /dev/null +++ b/serializers/wizard_serializer.rb @@ -0,0 +1,99 @@ +module CustomWizardWizardSerializerExtension + attributes :id, + :name, + :background, + :completed, + :required, + :min_trust, + :permitted, + :user, + :categories, + :uncategorized_category_id + + def id + object.id + end + + def include_id? + object.respond_to?(:id) + end + + def name + object.name + end + + def include_name? + object.respond_to?(:name) + end + + def background + object.background + end + + def include_background? + object.respond_to?(:background) + end + + def completed + object.completed? + end + + def include_completed? + object.completed? && + (!object.respond_to?(:multiple_submissions) || !object.multiple_submissions) && + !scope.is_admin? + end + + def min_trust + object.min_trust + end + + def include_min_trust? + object.respond_to?(:min_trust) + end + + def permitted + object.permitted? + end + + def include_permitted? + object.respond_to?(:permitted?) + end + + def include_start? + object.start && include_steps? + end + + def include_steps? + !include_completed? + end + + def required + object.required + end + + def include_required? + object.respond_to?(:required) + end + + def user + object.user + end + + def categories + begin + site = ::Site.new(scope) + ::ActiveModel::ArraySerializer.new(site.categories, each_serializer: BasicCategorySerializer) + rescue => e + puts "HERE IS THE ERROR: #{e.inspect}" + end + end + + def uncategorized_category_id + SiteSetting.uncategorized_category_id + end +end + +class WizardSerializer + prepend CustomWizardWizardSerializerExtension if SiteSetting.custom_wizard_enabled +end \ No newline at end of file diff --git a/serializers/wizard_step_serializer.rb b/serializers/wizard_step_serializer.rb new file mode 100644 index 00000000..0ee28202 --- /dev/null +++ b/serializers/wizard_step_serializer.rb @@ -0,0 +1,25 @@ +module CustomWizardWizardStepSerializerExtension + attributes :permitted, :permitted_message + + def title + return PrettyText.cook(object.title) if object.title + PrettyText.cook(I18n.t("#{object.key || i18n_key}.title", default: '')) + end + + def description + return object.description if object.description + PrettyText.cook(I18n.t("#{object.key || i18n_key}.description", default: '', base_url: Discourse.base_url)) + end + + def permitted + object.permitted + end + + def permitted_message + object.permitted_message + end +end + +class WizardStepSerializer + prepend CustomWizardWizardStepSerializerExtension if SiteSetting.custom_wizard_enabled +end \ No newline at end of file