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|}}
+ {{i18n (concat "admin.wizard.custom_field." key ".label")}} |
+ {{/each}}
+ |
+
+ {{#each customFields as |field|}}
+ {{custom-field-input
+ field=field
+ removeField=(action 'removeField')}}
+ {{/each}}
+
+ {{/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