From 4d1ee9007bb03503580142c65cea8adc620e6b5a Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Thu, 12 Dec 2019 15:43:11 +1100 Subject: [PATCH] Improve custom wizard serialization and add spec --- .../javascripts/wizard/models/custom.js.es6 | 2 +- controllers/custom_wizard/wizard.rb | 2 +- lib/custom_wizard/builder.rb | 6 + lib/custom_wizard/wizard.rb | 10 +- plugin.rb | 12 +- .../wizard_field_serializer.rb | 21 ++-- .../custom_wizard/wizard_serializer.rb | 51 +++++++++ .../wizard_step_serializer.rb | 15 +-- serializers/site_serializer.rb | 3 +- serializers/wizard_serializer.rb | 105 ------------------ spec/fixtures/wizard.json | 1 + .../custom_wizard/wizard_serializer_spec.rb | 58 ++++++++++ 12 files changed, 149 insertions(+), 137 deletions(-) rename serializers/{ => custom_wizard}/wizard_field_serializer.rb (67%) create mode 100644 serializers/custom_wizard/wizard_serializer.rb rename serializers/{ => custom_wizard}/wizard_step_serializer.rb (59%) delete mode 100644 serializers/wizard_serializer.rb create mode 100644 spec/serializers/custom_wizard/wizard_serializer_spec.rb diff --git a/assets/javascripts/wizard/models/custom.js.es6 b/assets/javascripts/wizard/models/custom.js.es6 index 003e80d5..28ae3f89 100644 --- a/assets/javascripts/wizard/models/custom.js.es6 +++ b/assets/javascripts/wizard/models/custom.js.es6 @@ -50,7 +50,7 @@ export function findCustomWizard(wizardId, params = {}) { } return ajax({ url, cache: false, dataType: 'json' }).then(result => { - const wizard = result.wizard; + const wizard = result.custom_wizard; if (!wizard) return null; if (!wizard.completed) { diff --git a/controllers/custom_wizard/wizard.rb b/controllers/custom_wizard/wizard.rb index a4403c89..19e550ce 100644 --- a/controllers/custom_wizard/wizard.rb +++ b/controllers/custom_wizard/wizard.rb @@ -26,7 +26,7 @@ class CustomWizard::WizardController < ::ApplicationController if builder.wizard.present? wizard = builder.build(builder_opts, params) - render_serialized(wizard, WizardSerializer) + render_serialized(wizard, ::CustomWizardSerializer) else render json: { error: I18n.t('wizard.none') } end diff --git a/lib/custom_wizard/builder.rb b/lib/custom_wizard/builder.rb index 2ccc1ec7..1dc7dbf6 100644 --- a/lib/custom_wizard/builder.rb +++ b/lib/custom_wizard/builder.rb @@ -245,6 +245,12 @@ class CustomWizard::Builder if field_template['type'] === 'category' params[:property] = field_template['property'] end + + if field_template['type'] === 'category' || + (field_template['type'] === 'dropdown' && + field_template['choices_preset'] === 'categories') + @wizard.needs_categories = true + end field = step.add_field(params) diff --git a/lib/custom_wizard/wizard.rb b/lib/custom_wizard/wizard.rb index 26f1c79a..f1b682ea 100644 --- a/lib/custom_wizard/wizard.rb +++ b/lib/custom_wizard/wizard.rb @@ -6,6 +6,7 @@ require_dependency 'wizard/builder' UserHistory.actions[:custom_wizard_step] = 1000 class CustomWizard::Wizard + include ActiveModel::SerializerSupport attr_reader :steps, :user attr_accessor :id, @@ -19,12 +20,15 @@ class CustomWizard::Wizard :after_signup, :required, :prompt_completion, - :restart_on_revisit + :restart_on_revisit, + :needs_categories def initialize(user=nil, attrs = {}) @steps = [] @user = user @first_step = nil + @required = false + @needs_categories = false attrs.each do |key, value| setter = "#{key}=" @@ -132,6 +136,10 @@ class CustomWizard::Wizard subject: "reset" ) end + + def categories + @categories ||= ::Site.new(Guardian.new(@user)).categories + end def self.after_signup rows = PluginStoreRow.where(plugin_name: 'custom_wizard') diff --git a/plugin.rb b/plugin.rb index c56942f7..58b690a7 100644 --- a/plugin.rb +++ b/plugin.rb @@ -63,16 +63,16 @@ after_initialize do '../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/site_serializer.rb', - '../serializers/wizard_serializer.rb', - '../serializers/wizard_step_serializer.rb', - '../serializers/wizard_field_serializer.rb' + '../serializers/custom_wizard/api_serializer.rb', + '../serializers/custom_wizard/basic_api_serializer.rb', + '../serializers/custom_wizard/wizard_field_serializer.rb', + '../serializers/custom_wizard/wizard_step_serializer.rb', + '../serializers/custom_wizard/wizard_serializer.rb', + '../serializers/site_serializer.rb' ].each do |path| load File.expand_path(path, __FILE__) end diff --git a/serializers/wizard_field_serializer.rb b/serializers/custom_wizard/wizard_field_serializer.rb similarity index 67% rename from serializers/wizard_field_serializer.rb rename to serializers/custom_wizard/wizard_field_serializer.rb index 873f8735..b1a7afad 100644 --- a/serializers/wizard_field_serializer.rb +++ b/serializers/custom_wizard/wizard_field_serializer.rb @@ -1,11 +1,14 @@ -module CustomWizardFieldSerializerExtension - extend ActiveSupport::Concern +# frozen_string_literal: true + +class CustomWizardFieldSerializer < ::WizardFieldSerializer - def self.prepended(klass) - klass.class_eval do - attributes :dropdown_none, :image, :file_types, :limit, :property - end - end + attributes :dropdown_none, + :image, + :file_types, + :limit, + :property + + has_many :fields, serializer: CustomWizardFieldSerializer, embed: :objects def label return object.label if object.label.present? @@ -44,8 +47,4 @@ module CustomWizardFieldSerializerExtension def property object.property end -end - -class WizardFieldSerializer - prepend CustomWizardFieldSerializerExtension if SiteSetting.custom_wizard_enabled end \ No newline at end of file diff --git a/serializers/custom_wizard/wizard_serializer.rb b/serializers/custom_wizard/wizard_serializer.rb new file mode 100644 index 00000000..9e0e77b2 --- /dev/null +++ b/serializers/custom_wizard/wizard_serializer.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +class CustomWizardSerializer < ::WizardSerializer + + attributes :id, + :name, + :background, + :completed, + :required, + :min_trust, + :permitted, + :uncategorized_category_id + + has_one :user, serializer: ::BasicUserSerializer, embed: :objects + has_many :steps, serializer: ::CustomWizardStepSerializer, embed: :objects + has_many :categories, serializer: ::BasicCategorySerializer, embed: :objects + + def completed + object.completed? + end + + def include_completed? + object.completed? && + (!object.respond_to?(:multiple_submissions) || !object.multiple_submissions) && + !scope.is_admin? + end + + def permitted + object.permitted? + end + + def include_start? + object.start && include_steps? + end + + def include_steps? + !include_completed? + end + + def include_categories? + object.needs_categories + end + + def uncategorized_category_id + SiteSetting.uncategorized_category_id + end + + def include_uncategorized_category_id? + object.needs_categories + end +end \ No newline at end of file diff --git a/serializers/wizard_step_serializer.rb b/serializers/custom_wizard/wizard_step_serializer.rb similarity index 59% rename from serializers/wizard_step_serializer.rb rename to serializers/custom_wizard/wizard_step_serializer.rb index e4e120bb..6c750270 100644 --- a/serializers/wizard_step_serializer.rb +++ b/serializers/custom_wizard/wizard_step_serializer.rb @@ -1,11 +1,8 @@ -module CustomWizardStepSerializerExtension - extend ActiveSupport::Concern +# frozen_string_literal: true + +class ::CustomWizardStepSerializer < ::WizardStepSerializer - def self.prepended(klass) - klass.class_eval do - attributes :permitted, :permitted_message - end - end + attributes :permitted, :permitted_message def title return PrettyText.cook(object.title) if object.title @@ -24,8 +21,4 @@ module CustomWizardStepSerializerExtension def permitted_message object.permitted_message end -end - -class WizardStepSerializer - prepend CustomWizardStepSerializerExtension if SiteSetting.custom_wizard_enabled end \ No newline at end of file diff --git a/serializers/site_serializer.rb b/serializers/site_serializer.rb index 64e37173..f899ae6e 100644 --- a/serializers/site_serializer.rb +++ b/serializers/site_serializer.rb @@ -1,4 +1,5 @@ ## TODO limit this to the first admin + module CustomWizardSiteSerializerExtension extend ActiveSupport::Concern @@ -23,6 +24,6 @@ module CustomWizardSiteSerializerExtension end end -class SiteSerializer +class ::SiteSerializer prepend CustomWizardSiteSerializerExtension if SiteSetting.custom_wizard_enabled end \ No newline at end of file diff --git a/serializers/wizard_serializer.rb b/serializers/wizard_serializer.rb deleted file mode 100644 index c39ecdb0..00000000 --- a/serializers/wizard_serializer.rb +++ /dev/null @@ -1,105 +0,0 @@ -module CustomWizardSerializerExtension - extend ActiveSupport::Concern - - def self.prepended(klass) - klass.class_eval do - attributes :id, - :name, - :background, - :completed, - :required, - :min_trust, - :permitted, - :user, - :categories, - :uncategorized_category_id - end - end - - 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 - [] - end - end - - def uncategorized_category_id - SiteSetting.uncategorized_category_id - end -end - -class WizardSerializer - prepend CustomWizardSerializerExtension if SiteSetting.custom_wizard_enabled -end \ No newline at end of file diff --git a/spec/fixtures/wizard.json b/spec/fixtures/wizard.json index 04c16fea..a9251f65 100644 --- a/spec/fixtures/wizard.json +++ b/spec/fixtures/wizard.json @@ -5,6 +5,7 @@ "save_submissions": true, "multiple_submissions": true, "after_signup": true, + "min_trust": 1, "theme_id": 4, "steps": [ { diff --git a/spec/serializers/custom_wizard/wizard_serializer_spec.rb b/spec/serializers/custom_wizard/wizard_serializer_spec.rb new file mode 100644 index 00000000..0ec28c43 --- /dev/null +++ b/spec/serializers/custom_wizard/wizard_serializer_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe CustomWizardSerializer do + fab!(:user) { Fabricate(:user) } + fab!(:category) { Fabricate(:category) } + + let!(:template) do + JSON.parse(File.open( + "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json" + ).read) + end + + let(:dropdown_categories_field) {{"id": "dropdown_categories","type": "dropdown","label": "Dropdown Categories","choices_type": "preset","choices_preset": "categories"}} + let(:category_field) {{"id": "category","type": "category","limit": "1","label": "Category"}} + + def build_wizard(t = template, u = user, build_opts = {}, params = {}) + CustomWizard::Wizard.add_wizard(t) + CustomWizard::Builder.new(u, 'welcome').build(build_opts, params) + end + + it 'should return the wizard attributes' do + json = CustomWizardSerializer.new(build_wizard, scope: Guardian.new(user)).as_json + expect(json[:custom_wizard][:id]).to eq("welcome") + expect(json[:custom_wizard][:name]).to eq("Welcome") + expect(json[:custom_wizard][:background]).to eq("#006da3") + expect(json[:custom_wizard][:required]).to eq(false) + expect(json[:custom_wizard][:min_trust]).to eq(1) + end + + it "should return the wizard user attributes" do + json = CustomWizardSerializer.new(build_wizard, scope: Guardian.new(user)).as_json + expect(json[:custom_wizard][:permitted]).to eq(true) + expect(json[:custom_wizard][:user]).to eq(BasicUserSerializer.new(user, root: false).as_json) + end + + it "should not return category attributes if there are no category fields" do + json = CustomWizardSerializer.new(build_wizard, scope: Guardian.new(user)).as_json + expect(json[:custom_wizard][:categories].present?).to eq(false) + expect(json[:custom_wizard][:uncategorized_category_id].present?).to eq(false) + end + + it "should return category attributes if there are dropdown category fields" do + template['steps'][0]['fields'][0] = dropdown_categories_field + json = CustomWizardSerializer.new(build_wizard(template), scope: Guardian.new(user)).as_json + expect(json[:custom_wizard][:categories].present?).to eq(true) + expect(json[:custom_wizard][:uncategorized_category_id].present?).to eq(true) + end + + it "should return category attributes if there is a category selector field" do + template['steps'][0]['fields'][0] = category_field + wizard = build_wizard(template) + json = CustomWizardSerializer.new(wizard, scope: Guardian.new(user)).as_json + expect(json[:custom_wizard][:categories].present?).to eq(true) + expect(json[:custom_wizard][:uncategorized_category_id].present?).to eq(true) + end +end \ No newline at end of file