diff --git a/assets/javascripts/discourse/components/custom-field-input.js.es6 b/assets/javascripts/discourse/components/custom-field-input.js.es6 new file mode 100644 index 00000000..4b1be935 --- /dev/null +++ b/assets/javascripts/discourse/components/custom-field-input.js.es6 @@ -0,0 +1,45 @@ +import Component from "@ember/component"; +import discourseComputed, { discourseObserve } from "discourse-common/utils/decorators"; +import { or } from "@ember/object/computed"; + +const generateContent = function(array, type) { + return array.map(key => ({ + id: key, + name: I18n.t(`admin.wizard.custom_field.${type}.${key}`) + })); +} + +export default Component.extend({ + tagName: 'tr', + topicSerializers: ['topic_view', 'topic_list_item'], + postSerializers: ['post'], + categorySerializers: ['basic_category', 'topic_view', 'topic_list_item'], + klassContent: generateContent(['topic', 'post', 'group', 'category'], 'klass'), + typeContent: generateContent(['string', 'boolean', 'integer', 'json'], 'type'), + showInputs: or('field.new', 'field.edit'), + + @discourseComputed('field.klass') + serializerContent(klass) { + const serializers = this.get(`${klass}Serializers`); + + if (serializers) { + return generateContent(serializers, 'serializers'); + } else { + return []; + } + }, + + actions: { + edit() { + this.set('field.edit', true); + }, + + close() { + if (this.field.edit) { + this.set('field.edit', false); + } else { + this.removeField(this.field); + } + } + } +}); \ No newline at end of file diff --git a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 index 8fcca367..dbfa4e93 100644 --- a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 @@ -29,7 +29,7 @@ export default Component.extend(UndoChanges, { hasCustomFields: or('basicTopicFields', 'updateProfile', 'createGroup', 'createCategory'), basicTopicFields: or('createTopic', 'sendMessage', 'openComposer'), publicTopicFields: or('createTopic', 'openComposer'), - showSkipRedirect: or('createTopic', 'sendMessage'), + showPostAdvanced: or('createTopic', 'sendMessage'), actionTypes: Object.keys(wizardSchema.action.types).map(type => { return { id: type, diff --git a/assets/javascripts/discourse/components/wizard-mapper-selector.js.es6 b/assets/javascripts/discourse/components/wizard-mapper-selector.js.es6 index 7d37f74f..5a8c7d63 100644 --- a/assets/javascripts/discourse/components/wizard-mapper-selector.js.es6 +++ b/assets/javascripts/discourse/components/wizard-mapper-selector.js.es6 @@ -21,9 +21,11 @@ export default Component.extend({ showGroup: computed('activeType', function() { return this.showInput('group') }), showUser: computed('activeType', function() { return this.showInput('user') }), showList: computed('activeType', function() { return this.showInput('list') }), + showCustomField: computed('activeType', function() { return this.showInput('customField') }), textEnabled: computed('options.textSelection', 'inputType', function() { return this.optionEnabled('textSelection') }), wizardFieldEnabled: computed('options.wizardFieldSelection', 'inputType', function() { return this.optionEnabled('wizardFieldSelection') }), wizardActionEnabled: computed('options.wizardActionSelection', 'inputType', function() { return this.optionEnabled('wizardActionSelection') }), + customFieldEnabled: computed('options.customFieldSelection', 'inputType', function() { return this.optionEnabled('customFieldSelection') }), userFieldEnabled: computed('options.userFieldSelection', 'inputType', function() { return this.optionEnabled('userFieldSelection') }), userFieldOptionsEnabled: computed('options.userFieldOptionsSelection', 'inputType', function() { return this.optionEnabled('userFieldOptionsSelection') }), categoryEnabled: computed('options.categorySelection', 'inputType', function() { return this.optionEnabled('categorySelection') }), @@ -34,7 +36,7 @@ export default Component.extend({ groups: alias('site.groups'), categories: alias('site.categories'), - showComboBox: or('showWizardField', 'showWizardAction', 'showUserField', 'showUserFieldOptions'), + showComboBox: or('showWizardField', 'showWizardAction', 'showUserField', 'showUserFieldOptions', 'showCustomField'), showMultiSelect: or('showCategory', 'showGroup'), hasTypes: gt('selectorTypes.length', 1), showTypes: false, @@ -88,7 +90,8 @@ export default Component.extend({ 'showController.wizard.actions.[]', 'showController.userFields.[]', 'showController.currentField.id', - 'showController.currentAction.id' + 'showController.currentAction.id', + 'showController.customFields' ) comboBoxContent( activeType, @@ -96,7 +99,8 @@ export default Component.extend({ wizardActions, userFields, currentFieldId, - currentActionId + currentActionId, + customFields ) { let content; @@ -139,6 +143,10 @@ export default Component.extend({ content = userFields; } + if (activeType === 'customField') { + content = customFields; + } + return content; }, diff --git a/assets/javascripts/discourse/controllers/admin-wizards-custom-fields.js.es6 b/assets/javascripts/discourse/controllers/admin-wizards-custom-fields.js.es6 new file mode 100644 index 00000000..9ed7762c --- /dev/null +++ b/assets/javascripts/discourse/controllers/admin-wizards-custom-fields.js.es6 @@ -0,0 +1,42 @@ +import Controller from "@ember/controller"; +import EmberObject from '@ember/object'; +import { ajax } from 'discourse/lib/ajax'; +import { popupAjaxError } from 'discourse/lib/ajax-error'; + +export default Controller.extend({ + fieldKeys: ['klass', 'type', 'serializers', 'name'], + + actions: { + addField() { + this.get('customFields').pushObject( + EmberObject.create({ + new: true + }) + ); + }, + + removeField(field) { + this.get('customFields').removeObject(field); + }, + + saveFields() { + this.set('saving', true); + ajax(`/admin/wizards/custom-fields`, { + type: 'PUT', + dataType: 'json', + contentType: 'application/json', + data: JSON.stringify({ + custom_fields: this.customFields + }) + }).then(result => { + if (result.success) { + this.set('saveIcon', 'check'); + } else { + this.set('saveIcon', 'times'); + } + setTimeout(() => this.set('saveIcon', ''), 5000); + }).finally(() => this.set('saving', false)) + .catch(popupAjaxError); + } + } +}); \ No newline at end of file diff --git a/assets/javascripts/discourse/custom-wizard-admin-route-map.js.es6 b/assets/javascripts/discourse/custom-wizard-admin-route-map.js.es6 index c2722816..97157964 100644 --- a/assets/javascripts/discourse/custom-wizard-admin-route-map.js.es6 +++ b/assets/javascripts/discourse/custom-wizard-admin-route-map.js.es6 @@ -7,6 +7,8 @@ export default { this.route('adminWizardsWizardShow', { path: '/:wizardId/', resetNamespace: true }); }); + this.route('adminWizardsCustomFields', { path: '/custom-fields', resetNamespace: true }); + this.route('adminWizardsSubmissions', { path: '/submissions', resetNamespace: true }, function() { this.route('adminWizardsSubmissionsShow', { path: '/:wizardId/', resetNamespace: true }); }) diff --git a/assets/javascripts/discourse/lib/wizard-mapper.js.es6 b/assets/javascripts/discourse/lib/wizard-mapper.js.es6 index 470a78c4..6fc50588 100644 --- a/assets/javascripts/discourse/lib/wizard-mapper.js.es6 +++ b/assets/javascripts/discourse/lib/wizard-mapper.js.es6 @@ -86,7 +86,8 @@ const selectionTypes = [ 'group', 'category', 'tag', - 'user' + 'user', + 'customField' ] function defaultSelectionType(inputType, options = {}) { diff --git a/assets/javascripts/discourse/lib/wizard-schema.js.es6 b/assets/javascripts/discourse/lib/wizard-schema.js.es6 index 840b84a5..7d34a79d 100644 --- a/assets/javascripts/discourse/lib/wizard-schema.js.es6 +++ b/assets/javascripts/discourse/lib/wizard-schema.js.es6 @@ -117,7 +117,8 @@ const action = { tags: null, visible: null, custom_fields: null, - skip_redirect: null + skip_redirect: null, + suppress_notifications: null, }, send_message: { title: null, @@ -127,7 +128,8 @@ const action = { skip_redirect: null, custom_fields: null, required: null, - recipient: null + recipient: null, + suppress_notifications: null }, open_composer: { title: null, @@ -218,6 +220,7 @@ const action = { 'code', 'custom_fields', 'skip_redirect', + 'suppress_notifications', 'required' ], required: [ diff --git a/assets/javascripts/discourse/routes/admin-wizards-custom-fields.js.es6 b/assets/javascripts/discourse/routes/admin-wizards-custom-fields.js.es6 new file mode 100644 index 00000000..c6775477 --- /dev/null +++ b/assets/javascripts/discourse/routes/admin-wizards-custom-fields.js.es6 @@ -0,0 +1,13 @@ +import DiscourseRoute from "discourse/routes/discourse"; +import { ajax } from 'discourse/lib/ajax'; +import { A } from "@ember/array"; + +export default DiscourseRoute.extend({ + model() { + return ajax('/admin/wizards/custom-fields'); + }, + + setupController(controller, model) { + controller.set('customFields', A(model || [])); + } +}); \ No newline at end of file diff --git a/assets/javascripts/discourse/routes/admin-wizards-wizard-show.js.es6 b/assets/javascripts/discourse/routes/admin-wizards-wizard-show.js.es6 index f8dd8479..21f3bb1b 100644 --- a/assets/javascripts/discourse/routes/admin-wizards-wizard-show.js.es6 +++ b/assets/javascripts/discourse/routes/admin-wizards-wizard-show.js.es6 @@ -2,6 +2,7 @@ import CustomWizard from '../models/custom-wizard'; import { ajax } from 'discourse/lib/ajax'; import DiscourseRoute from "discourse/routes/discourse"; import I18n from "I18n"; +import { selectKitContent } from '../lib/wizard'; export default DiscourseRoute.extend({ model(params) { @@ -32,6 +33,7 @@ export default DiscourseRoute.extend({ wizardList: parentModel.wizard_list, fieldTypes, userFields: parentModel.userFields, + customFields: selectKitContent(parentModel.custom_fields.map(f => f.name)), apis: parentModel.apis, themes: parentModel.themes, wizard, diff --git a/assets/javascripts/discourse/routes/admin-wizards-wizard.js.es6 b/assets/javascripts/discourse/routes/admin-wizards-wizard.js.es6 index 0ba204f3..588936f8 100644 --- a/assets/javascripts/discourse/routes/admin-wizards-wizard.js.es6 +++ b/assets/javascripts/discourse/routes/admin-wizards-wizard.js.es6 @@ -1,6 +1,7 @@ import DiscourseRoute from "discourse/routes/discourse"; import { buildFieldTypes } from '../lib/wizard-schema'; -import { set } from "@ember/object"; +import EmberObject, { set } from "@ember/object"; +import { A } from "@ember/array"; import { all } from "rsvp"; import { ajax } from 'discourse/lib/ajax'; @@ -62,7 +63,8 @@ export default DiscourseRoute.extend({ setupController(controller, model) { controller.setProperties({ wizardList: model.wizard_list, - wizardId: this.currentWizard() + wizardId: this.currentWizard(), + custom_fields: A(model.custom_fields.map(f => EmberObject.create(f))) }); }, diff --git a/assets/javascripts/discourse/templates/admin-wizards-custom-fields.hbs b/assets/javascripts/discourse/templates/admin-wizards-custom-fields.hbs new file mode 100644 index 00000000..a79ff3a9 --- /dev/null +++ b/assets/javascripts/discourse/templates/admin-wizards-custom-fields.hbs @@ -0,0 +1,38 @@ +
+

{{i18n 'admin.wizard.custom_field.nav_label'}}

+ +
+ {{#if saving}} + {{loading-spinner size="small"}} + {{else}} + {{#if saveIcon}} + {{d-icon saveIcon}} + {{/if}} + {{/if}} + {{d-button + label="admin.wizard.custom_field.save" + action="saveFields"}} + {{d-button + label="admin.wizard.custom_field.add" + icon="plus" + action="addField"}} +
+
+ +
+ {{#if customFields}} + + + {{#each fieldKeys as |key|}} + + {{/each}} + + + {{#each customFields as |field|}} + {{custom-field-input + field=field + removeField=(action 'removeField')}} + {{/each}} +
{{i18n (concat "admin.wizard.custom_field." key ".label")}}
+ {{/if}} +
diff --git a/assets/javascripts/discourse/templates/admin-wizards.hbs b/assets/javascripts/discourse/templates/admin-wizards.hbs index c0bd6b27..53ec86a6 100644 --- a/assets/javascripts/discourse/templates/admin-wizards.hbs +++ b/assets/javascripts/discourse/templates/admin-wizards.hbs @@ -1,5 +1,6 @@ {{#admin-nav}} {{nav-item route='adminWizardsWizard' label='admin.wizard.nav_label'}} + {{nav-item route='adminWizardsCustomFields' label='admin.wizard.custom_field.nav_label'}} {{nav-item route='adminWizardsSubmissions' label='admin.wizard.submissions.nav_label'}} {{#if siteSettings.wizard_apis_enabled}} {{nav-item route='adminWizardsApi' label='admin.wizard.api.nav_label'}} diff --git a/assets/javascripts/discourse/templates/components/custom-field-input.hbs b/assets/javascripts/discourse/templates/components/custom-field-input.hbs new file mode 100644 index 00000000..fdb3d26d --- /dev/null +++ b/assets/javascripts/discourse/templates/components/custom-field-input.hbs @@ -0,0 +1,44 @@ +{{#if showInputs}} + + {{combo-box + value=field.klass + content=klassContent + none="admin.wizard.custom_field.klass.select" + onChange=(action (mut field.klass))}} + + + {{combo-box + value=field.type + content=typeContent + none="admin.wizard.custom_field.type.select" + onChange=(action (mut field.type))}} + + + {{multi-select + value=field.serializers + content=serializerContent + none="admin.wizard.custom_field.serializers.select" + onChange=(action (mut field.serializers))}} + + + {{input + value=field.name + placeholder=(i18n "admin.wizard.custom_field.klass.select")}} + + + {{d-button action="close" icon="times"}} + +{{else}} + + + + {{#each field.serializers as |serializer|}} + + {{/each}} + + + + {{d-button action="edit" icon="pencil-alt"}} + {{d-button action="close" icon="times"}} + +{{/if}} \ No newline at end of file diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs index 03565ab8..265da2a3 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs @@ -733,7 +733,9 @@ onUpdate=(action 'mappedFieldUpdated') options=(hash inputTypes='association' + customFieldSelection='key' wizardFieldSelection='value' + wizardActionSelection='value' userFieldSelection='value' keyPlaceholder='admin.wizard.action.custom_fields.key' context='action' @@ -764,7 +766,7 @@ {{/if}} - {{#if showSkipRedirect}} + {{#if showPostAdvanced}}
@@ -778,6 +780,20 @@
+ +
+
+ +
+ +
+ {{input type='checkbox' checked=action.suppress_notifications}} + + + {{i18n 'admin.wizard.action.suppress_notifications.description' type='topic'}} + +
+
{{/if}} {{#if routeTo}} diff --git a/assets/stylesheets/common/wizard-admin.scss b/assets/stylesheets/common/wizard-admin.scss index 99fa857e..0b07475d 100644 --- a/assets/stylesheets/common/wizard-admin.scss +++ b/assets/stylesheets/common/wizard-admin.scss @@ -535,3 +535,35 @@ background-color: $secondary; border: 1px solid $primary-medium; } + +.admin-wizards-custom-fields { + .select-kit { + width: 200px; + } + + .select-kit.multi-select { + width: 200px; + + .choices .choice, + .select-kit-filter .filter-input { + height: 25px; + min-height: 25px; + } + } + + input[type="text"] { + margin: 0; + } + + td { + vertical-align: top; + } + + td:not(:last-of-type) { + min-width: 230px; + } + + td:last-of-type { + text-align: right; + } +} diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 65e31c96..39137f57 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -102,6 +102,7 @@ en: tag: "tag" group: "group" list: "list" + custom_field: "custom field" placeholder: text: "Enter text" @@ -115,6 +116,7 @@ en: tag: "Select tag" group: "Select group" list: "Enter item" + custom_field: "Select field" error: failed: "failed to save wizard" @@ -203,6 +205,9 @@ en: skip_redirect: label: "Redirect" description: "Don't redirect the user to this {{type}} after the wizard completes" + suppress_notifications: + label: "Suppress Notifications" + description: "Suppress normal notifications triggered by post creation" send_message: label: "Send Message" recipient: "Recipient" @@ -274,6 +279,36 @@ en: visibility_level: Visibility Level members_visibility_level: Members Visibility Level + custom_field: + nav_label: "Custom Fields" + add: "Add Custom Field" + save: "Save Custom Fields" + name: + label: "Name" + select: "Enter a name" + type: + label: "Type" + select: "Select a type" + string: "String" + integer: "Integer" + boolean: "Boolean" + json: "JSON" + klass: + label: "Class" + select: "Select a class" + post: "Post" + category: "Category" + topic: "Topic" + group: "Group" + user: "User" + serializers: + label: "Serializers" + select: "Select serializers" + topic_view: "Topic View" + topic_list_item: "Topic List Item" + basic_category: "Category" + post: "Post" + submissions: nav_label: "Submissions" title: "{{name}} Submissions" diff --git a/config/routes.rb b/config/routes.rb index 8f754d08..a765a809 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -19,6 +19,9 @@ Discourse::Application.routes.append do put 'admin/wizards/wizard/:wizard_id' => 'admin_wizard#save' delete 'admin/wizards/wizard/:wizard_id' => 'admin_wizard#remove' + get 'admin/wizards/custom-fields' => 'admin_custom_fields#index' + put 'admin/wizards/custom-fields' => 'admin_custom_fields#update' + get 'admin/wizards/submissions' => 'admin_submissions#index' get 'admin/wizards/submissions/:wizard_id' => 'admin_submissions#show' get 'admin/wizards/submissions/:wizard_id/download' => 'admin_submissions#download' diff --git a/controllers/custom_wizard/admin/admin.rb b/controllers/custom_wizard/admin/admin.rb index fe438e5d..5da337a4 100644 --- a/controllers/custom_wizard/admin/admin.rb +++ b/controllers/custom_wizard/admin/admin.rb @@ -11,4 +11,8 @@ class CustomWizard::AdminController < ::Admin::AdminController @wizard = CustomWizard::Wizard.create(params[:wizard_id].underscore) raise Discourse::InvalidParameters.new(:wizard_id) unless @wizard end + + def custom_field_list + serialize_data(CustomWizard::CustomField.list, CustomWizard::CustomFieldSerializer) + end end \ No newline at end of file diff --git a/controllers/custom_wizard/admin/custom_fields.rb b/controllers/custom_wizard/admin/custom_fields.rb new file mode 100644 index 00000000..6359d08f --- /dev/null +++ b/controllers/custom_wizard/admin/custom_fields.rb @@ -0,0 +1,47 @@ +class CustomWizard::AdminCustomFieldsController < CustomWizard::AdminController + def index + render_json_dump(custom_field_list) + end + + def update + custom_fields = custom_field_params[:custom_fields].map do |data| + CustomWizard::CustomField.new(data.to_h) + end + + custom_fields.each do |custom_field| + custom_field.validate + + unless custom_field.valid? + raise Discourse::InvalidParameters, + custom_field.errors.full_messages.join("\n\n") + end + end + + all_fields_saved = true + + custom_fields.each do |field| + unless field.save + all_fields_saved = false + end + end + + if all_fields_saved + render json: success_json + else + render json: error_json + end + end + + private + + def custom_field_params + params.permit( + custom_fields: [ + :klass, + :name, + :type, + serializers: [] + ] + ) + end +end \ No newline at end of file diff --git a/controllers/custom_wizard/admin/wizard.rb b/controllers/custom_wizard/admin/wizard.rb index 0594de5e..9a0dc4cf 100644 --- a/controllers/custom_wizard/admin/wizard.rb +++ b/controllers/custom_wizard/admin/wizard.rb @@ -7,7 +7,8 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController CustomWizard::Wizard.list(current_user), each_serializer: CustomWizard::BasicWizardSerializer ), - field_types: CustomWizard::Field.types + field_types: CustomWizard::Field.types, + custom_fields: custom_field_list ) end @@ -110,6 +111,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController :type, :code, :skip_redirect, + :suppress_notifications, :post, :post_builder, :post_template, diff --git a/lib/custom_wizard/action.rb b/lib/custom_wizard/action.rb index 18252f85..b99466ae 100644 --- a/lib/custom_wizard/action.rb +++ b/lib/custom_wizard/action.rb @@ -60,12 +60,18 @@ class CustomWizard::Action end def send_message - if action['required'].present? && data[action['required']].blank? - log_error( - "required not present", - "required: #{action['required']}; data: #{data[action['required']]}" - ) - return + + if action['required'].present? + required = CustomWizard::Mapper.new( + inputs: action['required'], + data: data, + user: user + ).perform + + if required.blank? + log_error("required input not present") + return + end end params = basic_topic_params @@ -448,17 +454,32 @@ class CustomWizard::Action user: user ).perform + registered_fields = CustomWizard::CustomField.list + field_map.each do |field| keyArr = field[:key].split('.') value = field[:value] - if keyArr.first === 'topic' + if keyArr.length > 1 + klass = keyArr.first + name = keyArr.last + else + name = keyArr.first + end + + + registered = registered_fields.select { |f| f.name == name } + if registered.first.present? + klass = registered.first.klass + end + + if klass === 'topic' params[:topic_opts] ||= {} params[:topic_opts][:custom_fields] ||= {} - params[:topic_opts][:custom_fields][keyArr.last] = value + params[:topic_opts][:custom_fields][name] = value else params[:custom_fields] ||= {} - params[:custom_fields][keyArr.last.to_sym] = value + params[:custom_fields][name] = value end end end @@ -481,6 +502,8 @@ class CustomWizard::Action mapper.interpolate(action['post_template']) : data[action['post']] + params[:import_mode] = ActiveRecord::Type::Boolean.new.cast(action['suppress_notifications']) + add_custom_fields(params) end diff --git a/lib/custom_wizard/custom_field.rb b/lib/custom_wizard/custom_field.rb new file mode 100644 index 00000000..b658a958 --- /dev/null +++ b/lib/custom_wizard/custom_field.rb @@ -0,0 +1,92 @@ +class ::CustomWizard::CustomField + include HasErrors + include ActiveModel::Serialization + + CLASSES ||= ["topic", "group", "category", "post"] + SERIALIZERS ||= ["topic_view", "topic_list_item", "post", "basic_category"] + TYPES ||= ["string", "boolean", "integer", "json"] + ATTRS ||= ["name", "klass", "type", "serializers"] + KEY ||= "custom_wizard_custom_fields" + + def initialize(data) + data = data.with_indifferent_access + + ATTRS.each do |attr| + self.class.class_eval { attr_accessor attr } + send("#{attr}=", data[attr]) if data[attr].present? + end + end + + def save + validate + + if valid? + data = {} + name = nil + + ATTRS.each do |attr| + value = send(attr) + + if attr == 'name' + name = value.parameterize(separator: '_') + else + data[attr] = value + end + end + + PluginStore.set(KEY, name, data) + else + false + end + end + + def validate + ATTRS.each do |attr| + value = send(attr) + + if value.blank? + add_error("Attribute required: #{attr}") + next + end + + if attr == 'klass' && CLASSES.exclude?(value) + add_error("Unsupported class: #{value}") + end + + if attr == 'serializers' && value.present? && (SERIALIZERS & value).empty? + add_error("Unsupported serializer: #{value}") + end + + if attr == 'type' && TYPES.exclude?(value) + add_error("Unsupported type: #{value}") + end + + if attr == 'name' && value.length < 3 + add_error("Field name is too short") + end + end + end + + def valid? + errors.blank? + end + + def self.list + PluginStoreRow.where(plugin_name: KEY) + .map do |record| + data = JSON.parse(record.value) + data[:name] = record.key + self.new(data) + end + end + + def self.list_by(attr, value) + self.list.select do |cf| + if attr == 'serializers' + cf.send(attr).include?(value) + else + cf.send(attr) == value + end + end + end +end \ No newline at end of file diff --git a/plugin.rb b/plugin.rb index 544db890..48537e28 100644 --- a/plugin.rb +++ b/plugin.rb @@ -43,6 +43,7 @@ after_initialize do ../controllers/custom_wizard/admin/api.rb ../controllers/custom_wizard/admin/logs.rb ../controllers/custom_wizard/admin/transfer.rb + ../controllers/custom_wizard/admin/custom_fields.rb ../controllers/custom_wizard/wizard.rb ../controllers/custom_wizard/steps.rb ../jobs/clear_after_time_wizard.rb @@ -51,6 +52,7 @@ after_initialize do ../lib/custom_wizard/action_result.rb ../lib/custom_wizard/action.rb ../lib/custom_wizard/builder.rb + ../lib/custom_wizard/custom_field.rb ../lib/custom_wizard/field.rb ../lib/custom_wizard/mapper.rb ../lib/custom_wizard/log.rb @@ -69,6 +71,7 @@ after_initialize do ../serializers/custom_wizard/api_serializer.rb ../serializers/custom_wizard/basic_api_serializer.rb ../serializers/custom_wizard/basic_wizard_serializer.rb + ../serializers/custom_wizard/custom_field_serializer.rb ../serializers/custom_wizard/wizard_field_serializer.rb ../serializers/custom_wizard/wizard_step_serializer.rb ../serializers/custom_wizard/wizard_serializer.rb @@ -164,5 +167,30 @@ after_initialize do import_files(DiscoursePluginRegistry.stylesheets["wizard_custom"]) end + CustomWizard::CustomField::CLASSES.each do |klass| + add_model_callback(klass.to_sym, :after_initialize) do + CustomWizard::CustomField.list_by('klass', klass).each do |field| + klass.classify + .constantize + .register_custom_field_type(field.name, field.type.to_sym) + end + end + end + + CustomWizard::CustomField::SERIALIZERS.each do |serializer_klass| + "#{serializer_klass}_serializer".classify.constantize.class_eval do + CustomWizard::CustomField.list_by('serializers', serializer_klass).each do |field| + attributes(field.name.to_sym) + class_eval %{def #{field.name} + if "#{serializer_klass}" == "topic_view" + object.topic.custom_fields["#{field.name}"] + else + object.custom_fields["#{field.name}"] + end + end} + end + end + end + DiscourseEvent.trigger(:custom_wizard_ready) end diff --git a/serializers/custom_wizard/custom_field_serializer.rb b/serializers/custom_wizard/custom_field_serializer.rb new file mode 100644 index 00000000..14e3fb32 --- /dev/null +++ b/serializers/custom_wizard/custom_field_serializer.rb @@ -0,0 +1,3 @@ +class CustomWizard::CustomFieldSerializer < ApplicationSerializer + attributes :klass, :name, :type, :serializers +end \ No newline at end of file