diff --git a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 index 75000d8b..4957dbc6 100644 --- a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 @@ -5,6 +5,8 @@ const ACTION_TYPES = [ { id: 'update_profile', name: 'Update Profile' }, { id: 'send_message', name: 'Send Message' }, { id: 'send_to_api', name: 'Send to API' } + { id: 'add_to_group', name: 'Add to Group' }, + { id: 'route_to', name: 'Route To' } ]; const PROFILE_FIELDS = [ @@ -29,33 +31,10 @@ export default Ember.Component.extend({ sendMessage: Ember.computed.equal('action.type', 'send_message'), sendToApi: Ember.computed.equal('action.type', 'send_to_api'), apiEmpty: Ember.computed.empty('action.api'), + addToGroup: Ember.computed.equal('action.type', 'add_to_group'), + routeTo: Ember.computed.equal('action.type', 'route_to'), disableId: Ember.computed.not('action.isNew'), - @computed('currentStepId', 'wizard.save_submissions') - availableFields(currentStepId, saveSubmissions) { - const allSteps = this.get('wizard.steps'); - let steps = allSteps; - let fields = []; - - if (!saveSubmissions) { - steps = [allSteps.findBy('id', currentStepId)]; - } - - steps.forEach((s) => { - if (s.fields && s.fields.length > 0) { - let stepFields = s.fields.map((f) => { - return Ember.Object.create({ - id: f.id, - label: `${f.id} (${s.id})` - }); - }); - fields.push(...stepFields); - } - }); - - return fields; - }, - @computed('availableFields') builderWizardFields(fields) { return fields.map((f) => ` w{${f.id}}`); diff --git a/assets/javascripts/discourse/components/wizard-custom-field.js.es6 b/assets/javascripts/discourse/components/wizard-custom-field.js.es6 index bdef2d67..19cc0ba2 100644 --- a/assets/javascripts/discourse/components/wizard-custom-field.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-field.js.es6 @@ -15,7 +15,13 @@ export default Ember.Component.extend({ @computed() presetChoices() { return [ - { id: 'categories', name: I18n.t('admin.wizard.field.choices_preset.categories') } + { + id: 'categories', + name: I18n.t('admin.wizard.field.choices_preset.categories') + },{ + id: 'groups', + name: I18n.t('admin.wizard.field.choices_preset.groups') + } ]; }, }); diff --git a/assets/javascripts/discourse/components/wizard-custom-input.js.es6 b/assets/javascripts/discourse/components/wizard-custom-input.js.es6 index 7d5a1271..21e27146 100644 --- a/assets/javascripts/discourse/components/wizard-custom-input.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-input.js.es6 @@ -5,6 +5,7 @@ export default Ember.Component.extend({ classNames: 'custom-input', noneKey: 'admin.wizard.select_field', noneValue: 'admin.wizard.none', + connectorNone: 'admin.wizard.none', inputKey: 'admin.wizard.key', customDisabled: Ember.computed.alias('input.user_field'), diff --git a/assets/javascripts/discourse/components/wizard-custom-inputs.js.es6 b/assets/javascripts/discourse/components/wizard-custom-inputs.js.es6 index 21e839f0..6dca9d65 100644 --- a/assets/javascripts/discourse/components/wizard-custom-inputs.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-inputs.js.es6 @@ -1,4 +1,5 @@ export default Ember.Component.extend({ + classNames: 'custom-inputs', valuePlaceholder: 'admin.wizard.value', actions: { diff --git a/assets/javascripts/discourse/components/wizard-custom-step.js.es6 b/assets/javascripts/discourse/components/wizard-custom-step.js.es6 index f0d9c48f..11dac446 100644 --- a/assets/javascripts/discourse/components/wizard-custom-step.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-step.js.es6 @@ -1,4 +1,4 @@ -import { observes } from 'ember-addons/ember-computed-decorators'; +import { observes, default as computed } from 'ember-addons/ember-computed-decorators'; export default Ember.Component.extend({ classNames: 'wizard-custom-step', @@ -14,5 +14,62 @@ export default Ember.Component.extend({ currentField: fields.length ? fields[0] : null, currentAction: actions.length ? actions[0] : null }); - } + }, + + @computed('availableFields', 'wizard.steps') + requiredContent(availableFields, steps) { + let content = availableFields; + let actions = []; + + steps.forEach(s => { + actions.push(...s.actions); + }); + + actions.forEach(a => { + if (a.type === 'route_to' && a.code) { + content.push(Ember.Object.create({ + id: a.code, + label: "code (Route To)" + })); + } + }); + + return content; + }, + + @computed + requiredConnectorContent() { + const label = (id) => I18n.t(`admin.wizard.step.required_data.connector.${id}`); + return [ + { + id: 'equals', + label: label('equals') + } + ]; + }, + + @computed('step.id', 'wizard.save_submissions') + availableFields(currentStepId, saveSubmissions) { + const allSteps = this.get('wizard.steps'); + let steps = allSteps; + let fields = []; + + if (!saveSubmissions) { + steps = [allSteps.findBy('id', currentStepId)]; + } + + steps.forEach((s) => { + if (s.fields && s.fields.length > 0) { + let stepFields = s.fields.map((f) => { + return Ember.Object.create({ + id: f.id, + label: `${f.id} (${s.id})` + }); + }); + fields.push(...stepFields); + } + }); + + return fields; + }, }); diff --git a/assets/javascripts/discourse/models/custom-wizard.js.es6 b/assets/javascripts/discourse/models/custom-wizard.js.es6 index 6cb18535..7e8ad927 100644 --- a/assets/javascripts/discourse/models/custom-wizard.js.es6 +++ b/assets/javascripts/discourse/models/custom-wizard.js.es6 @@ -77,6 +77,8 @@ const CustomWizard = Discourse.Model.extend({ if (s.key) step['key'] = s.key; if (s.banner) step['banner'] = s.banner; if (s.raw_description) step['raw_description'] = s.raw_description; + if (s.required_data) step['required_data'] = s.required_data; + if (s.permitted_params) step['permitted_params'] = s.permitted_params; const fields = s.get('fields'); if (fields.length) { @@ -242,6 +244,8 @@ CustomWizard.reopenClass({ title: s.title, raw_description: s.raw_description, banner: s.banner, + required_data: s.required_data, + permitted_params: s.permitted_params, fields, actions, isNew: false diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs index 95384f64..59fa22ab 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs @@ -242,3 +242,44 @@ {{/if}} + +{{#if addToGroup}} +
+
+

{{i18n "admin.wizard.action.add_to_group.group_selection"}}

+
+
+ {{combo-box value=action.group_id + content=availableFields + nameProperty="label" + none='admin.wizard.select_field' + isDisabled=action.custom_group_enabled}} +
+ {{input type='checkbox' checked=action.custom_group_enabled}} + {{i18n 'admin.wizard.action.add_to_group.custom_group'}} + {{#if action.custom_group_enabled}} + {{input value=action.group_id}} + {{/if}} +
+
+
+{{/if}} + +{{#if routeTo}} +
+
+

{{i18n "admin.wizard.action.route_to.url"}}

+
+
+ {{input value=action.url}} +
+
+
+
+

{{i18n "admin.wizard.action.route_to.code"}}

+
+
+ {{input value=action.code}} +
+
+{{/if}} diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-input.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-input.hbs index 048f16e3..4e368de7 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-input.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-input.hbs @@ -6,7 +6,18 @@ {{/if}} -{{d-icon 'arrow-right'}} +
+ {{#if connectorContent}} + {{combo-box value=input.connector + content=connectorContent + nameProperty="label" + none=connectorNone}} + {{/if}} + + {{#if connectorKey}} + {{i18n connectorKey}} + {{/if}} +
{{#if valueContent}} diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-inputs.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-inputs.hbs index a8cc5805..f41f3d73 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-inputs.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-inputs.hbs @@ -2,6 +2,8 @@ {{wizard-custom-input input=input valueContent=valueContent keyContent=keyContent + connectorContent=connectorContent + connectorKey=connectorKey noneValue=noneValue valuePlaceholder=valuePlaceholder allowCustomField=allowCustomField diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-step.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-step.hbs index 0722cb6d..0d6eb618 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-step.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-step.hbs @@ -43,6 +43,30 @@
+
+
+

{{i18n 'admin.wizard.step.required_data.label'}}

+
+
+ {{wizard-custom-inputs inputs=step.required_data + inputKey='admin.wizard.step.required_data.key' + valueContent=requiredContent + connectorContent=requiredConnectorContent}} +
+
+ +
+
+

{{i18n 'admin.wizard.step.permitted_params.label'}}

+
+
+ {{wizard-custom-inputs inputs=step.permitted_params + inputKey='admin.wizard.step.permitted_params.key' + valuePlaceholder='admin.wizard.step.permitted_params.value' + connectorKey='admin.wizard.step.permitted_params.connector'}} +
+
+ {{wizard-links type="field" current=currentField items=step.fields}} {{#if currentField}} {{wizard-custom-field field=currentField types=wizard.fieldTypes removeField="removeField"}} @@ -50,7 +74,10 @@ {{wizard-links type="action" current=currentAction items=step.actions}} {{#if currentAction}} - {{wizard-custom-action action=currentAction wizard=wizard removeAction="removeAction" currentStepId=step.id}} + {{wizard-custom-action action=currentAction + wizard=wizard + removeAction="removeAction" + availableFields=availableFields}} {{/if}} diff --git a/assets/javascripts/wizard/components/custom-user-selector.js.es6 b/assets/javascripts/wizard/components/custom-user-selector.js.es6 index c553bd68..10bfba50 100644 --- a/assets/javascripts/wizard/components/custom-user-selector.js.es6 +++ b/assets/javascripts/wizard/components/custom-user-selector.js.es6 @@ -81,8 +81,7 @@ export default Ember.TextField.extend({ includeGroups, allowedUsers, includeMentionableGroups, - includeMessageableGroups, - group: self.get("group") + includeMessageableGroups }); return results; diff --git a/assets/javascripts/wizard/components/wizard-no-access.js.es6 b/assets/javascripts/wizard/components/wizard-no-access.js.es6 index 83fcc7da..0b222ec1 100644 --- a/assets/javascripts/wizard/components/wizard-no-access.js.es6 +++ b/assets/javascripts/wizard/components/wizard-no-access.js.es6 @@ -10,4 +10,4 @@ export default Ember.Component.extend({ CustomWizard.skip(this.get('wizardId')); } } -}) +}); diff --git a/assets/javascripts/wizard/controllers/custom-step.js.es6 b/assets/javascripts/wizard/controllers/custom-step.js.es6 index e273ef7b..fcfe2688 100644 --- a/assets/javascripts/wizard/controllers/custom-step.js.es6 +++ b/assets/javascripts/wizard/controllers/custom-step.js.es6 @@ -5,7 +5,9 @@ export default StepController.extend({ actions: { goNext(response) { const next = this.get('step.next'); - if (response.refresh_required) { + if (response.route_to) { + window.location.href = response.route_to; + } else if (response.refresh_required) { const id = this.get('wizard.id'); window.location.href = getUrl(`/w/${id}/steps/${next}`); } else { diff --git a/assets/javascripts/wizard/controllers/custom.js.es6 b/assets/javascripts/wizard/controllers/custom.js.es6 index 9e89a0b0..fc2eb947 100644 --- a/assets/javascripts/wizard/controllers/custom.js.es6 +++ b/assets/javascripts/wizard/controllers/custom.js.es6 @@ -1,3 +1,3 @@ export default Ember.Controller.extend({ queryParams: ['reset'] -}) +}); diff --git a/assets/javascripts/wizard/initializers/custom.js.es6 b/assets/javascripts/wizard/initializers/custom.js.es6 index c426514e..225f1f0f 100644 --- a/assets/javascripts/wizard/initializers/custom.js.es6 +++ b/assets/javascripts/wizard/initializers/custom.js.es6 @@ -71,6 +71,10 @@ export default { return index === 0 && !required; }.property('step.index', 'wizard.required'), + cookedTitle: function() { + return cook(this.get('step.title')); + }.property('step.title'), + cookedDescription: function() { return cook(this.get('step.description')); }.property('step.description'), diff --git a/assets/javascripts/wizard/models/custom.js.es6 b/assets/javascripts/wizard/models/custom.js.es6 index 90bd8985..4d12b169 100644 --- a/assets/javascripts/wizard/models/custom.js.es6 +++ b/assets/javascripts/wizard/models/custom.js.es6 @@ -24,20 +24,33 @@ CustomWizard.reopenClass({ finished(result) { let url = "/"; - if (result.redirect_to) { - url = result.redirect_to; + if (result.redirect_on_complete) { + url = result.redirect_on_complete; } window.location.href = getUrl(url); } }); -export function findCustomWizard(wizardId, opts = {}) { +export function findCustomWizard(wizardId, params = {}) { let url = `/w/${wizardId}`; - if (opts.reset) url += '?reset=true'; + + let paramKeys = Object.keys(params).filter(k => { + if (k === 'wizard_id') return false; + return !!params[k]; + }); + + if (paramKeys.length) { + url += '?'; + paramKeys.forEach((k,i) => { + if (i > 0) { + url += '&'; + } + url += `${k}=${params[k]}`; + }); + } return ajax({ url, cache: false, dataType: 'json' }).then(result => { const wizard = result.wizard; - if (!wizard) return null; if (!wizard.completed) { diff --git a/assets/javascripts/wizard/routes/custom-index.js.es6 b/assets/javascripts/wizard/routes/custom-index.js.es6 index 5e7a2914..c857753d 100644 --- a/assets/javascripts/wizard/routes/custom-index.js.es6 +++ b/assets/javascripts/wizard/routes/custom-index.js.es6 @@ -16,8 +16,13 @@ export default Ember.Route.extend({ const permitted = model.get('permitted'); const minTrust = model.get('min_trust'); const wizardId = model.get('id'); + const user = model.get('user'); + const name = model.get('name'); controller.setProperties({ + requiresLogin: !user, + user, + name, completed, notPermitted: !permitted, minTrust, diff --git a/assets/javascripts/wizard/routes/custom-step.js.es6 b/assets/javascripts/wizard/routes/custom-step.js.es6 index b72f8184..ae3e2ddf 100644 --- a/assets/javascripts/wizard/routes/custom-step.js.es6 +++ b/assets/javascripts/wizard/routes/custom-step.js.es6 @@ -15,9 +15,19 @@ export default Ember.Route.extend({ return model.set("wizardId", this.modelFor('custom').id); }, - setupController(controller, step) { - controller.setProperties({ - step, wizard: this.modelFor('custom') - }); + setupController(controller, model) { + let props = { + step: model, + wizard: this.modelFor('custom') + }; + + if (!model.permitted) { + props['stepMessage'] = { + state: 'not-permitted', + text: "You're not allowed to view this step." + }; + } + + controller.setProperties(props); } }); diff --git a/assets/javascripts/wizard/routes/custom.js.es6 b/assets/javascripts/wizard/routes/custom.js.es6 index dcdfbcb7..66c53bc9 100644 --- a/assets/javascripts/wizard/routes/custom.js.es6 +++ b/assets/javascripts/wizard/routes/custom.js.es6 @@ -4,10 +4,12 @@ import { findCustomWizard } from '../models/custom'; import { ajax } from 'wizard/lib/ajax'; export default Ember.Route.extend({ + beforeModel(transition) { + this.set('queryParams', transition.intent.queryParams); + }, + model(params) { - let opts = {}; - if (params.reset == 'true') opts['reset'] = true; - return findCustomWizard(params.wizard_id, opts); + return findCustomWizard(params.wizard_id, this.get('queryParams')); }, afterModel() { diff --git a/assets/javascripts/wizard/templates/components/wizard-step.hbs b/assets/javascripts/wizard/templates/components/wizard-step.hbs index 41cc336a..ae793060 100644 --- a/assets/javascripts/wizard/templates/components/wizard-step.hbs +++ b/assets/javascripts/wizard/templates/components/wizard-step.hbs @@ -1,6 +1,6 @@
{{#if step.title}} -

{{step.title}}

+

{{cookedTitle}}

{{/if}} {{#if step.description}} diff --git a/assets/javascripts/wizard/templates/custom.index.hbs b/assets/javascripts/wizard/templates/custom.index.hbs index 8c1a48ae..f6ac1df5 100644 --- a/assets/javascripts/wizard/templates/custom.index.hbs +++ b/assets/javascripts/wizard/templates/custom.index.hbs @@ -1,10 +1,15 @@ -{{#if completed}} - {{wizard-no-access text=(i18n 'wizard.completed') wizardId=wizardId}} +{{#if noWizard}} + {{wizard-no-access text=(i18n 'wizard.none') wizardId=wizardId}} {{else}} - {{#if notPermitted}} - {{wizard-no-access text=(i18n 'wizard.not_permitted' level=minTrust) wizardId=wizardId}} - {{/if}} - {{#if noWizard}} - {{wizard-no-access text=(i18n 'wizard.none') wizardId=wizardId}} + {{#if requiresLogin}} + {{wizard-no-access text=(i18n 'wizard.requires_login' name=name) wizardId=wizardId}} + {{else}} + {{#if notPermitted}} + {{wizard-no-access text=(i18n 'wizard.not_permitted' name=name level=minTrust) wizardId=wizardId}} + {{else}} + {{#if completed}} + {{wizard-no-access text=(i18n 'wizard.completed' name=name) wizardId=wizardId}} + {{/if}} + {{/if}} {{/if}} {{/if}} diff --git a/assets/javascripts/wizard/templates/custom.step.hbs b/assets/javascripts/wizard/templates/custom.step.hbs index 1264618f..b0a39637 100644 --- a/assets/javascripts/wizard/templates/custom.step.hbs +++ b/assets/javascripts/wizard/templates/custom.step.hbs @@ -1,9 +1,11 @@
{{stepMessage.text}}
-{{wizard-step step=step - wizard=wizard - goNext="goNext" - goBack=(action "goBack") - finished="finished" - showMessage="showMessage"}} +{{#if step.permitted}} + {{wizard-step step=step + wizard=wizard + goNext="goNext" + goBack=(action "goBack") + finished="finished" + showMessage="showMessage"}} +{{/if}} diff --git a/assets/stylesheets/wizard/wizard_composer.scss b/assets/stylesheets/wizard/wizard_composer.scss index 14b115ce..fa8c8a62 100644 --- a/assets/stylesheets/wizard/wizard_composer.scss +++ b/assets/stylesheets/wizard/wizard_composer.scss @@ -157,7 +157,12 @@ //// .d-editor { - max-height: 250px; + min-height: 200px; + + .d-editor-input { + resize: vertical; + flex: initial; + } } .d-editor-modal.hidden { diff --git a/assets/stylesheets/wizard/wizard_custom.scss b/assets/stylesheets/wizard/wizard_custom.scss index 63eca692..b718bf41 100644 --- a/assets/stylesheets/wizard/wizard_custom.scss +++ b/assets/stylesheets/wizard/wizard_custom.scss @@ -293,6 +293,13 @@ background-color: #e45735; color: #ffffff; } + + &.not-permitted { + height: 60px; + line-height: 60px; + background-color: #e45735; + color: #ffffff; + } } .p-list-box { diff --git a/assets/stylesheets/wizard_custom_admin.scss b/assets/stylesheets/wizard_custom_admin.scss index ab078fc4..0cfb4bb7 100644 --- a/assets/stylesheets/wizard_custom_admin.scss +++ b/assets/stylesheets/wizard_custom_admin.scss @@ -83,8 +83,13 @@ .setting-value { width: initial; - overflow: hidden; float: none; + display: flex; + + .custom-input .remove { + margin-left: 10px; + margin-top: 0; + } } } @@ -186,13 +191,18 @@ .custom-input { display: flex; - margin: 5px 0; + align-items: center; + margin-bottom: 10px; .d-icon { margin: 0 auto; text-align: center; } + input { + margin: 0; + } + input[disabled] { background-color: $primary-low; border-color: #ddd; @@ -206,6 +216,10 @@ margin: 0 auto; align-self: flex-start; } + + .connector { + margin: 0 10px; + } } .setting .add-custom-input { @@ -213,12 +227,12 @@ } .admin-contents .wizard-submissions { - padding: 0 20px; + width: 100%; display: inline-block; - overflow: scroll; - table { margin-top: 0; + display: inline-block; + overflow-x: scroll; } } @@ -450,3 +464,7 @@ padding: 20px; margin-bottom: 20px; } + +.wizard-step-contents{ + height: unset !important; +} diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 86423497..7634dcc5 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -72,6 +72,16 @@ en: banner: "Banner" banner_placeholder: "Image url" description: "Description" + required_data: + label: "Required Data" + key: 'Submission key' + connector: + equals: "Equals" + permitted_params: + label: "Permitted Params" + key: 'Param' + value: 'Submission key' + connector: "Save as" field: type: "Choose a type" header: "Fields" @@ -88,6 +98,7 @@ en: choices_preset: label: "Preset" categories: "Categories" + groups: "Groups" filter: "Preset Filter" choice: value: "Value" @@ -123,6 +134,16 @@ en: label: "Builder" user_fields: "User Fields: " wizard_fields: "Wizard Fields: " + placeholder: "Insert wizard fields using the field_id in w{}. Insert user fields using field key in u{}." + add_to_group: + label: "Add to Group" + group: "Group" + group_selection: "Group Selection" + custom_group: "Custom Group" + route_to: + label: "Route To" + url: "Url" + code: "Code" custom_title: "Custom Title" custom_category: label: "Custom Category" @@ -237,10 +258,11 @@ en: filter_placeholder: "Search..." wizard: - completed: "You have completed this wizard." - not_permitted: "You need to be trust level {{level}} or higher to access this wizard." + completed: "You have completed the {{name}} wizard." + not_permitted: "You need to be trust level {{level}} or higher to access the {{name}} wizard." none: "There is no wizard here." return_to_site: "Return to {{siteName}}" + requires_login: "You need to be logged in to access the {{name}} wizard." wizard_composer: show_preview: "Preview Post" diff --git a/controllers/wizard.rb b/controllers/wizard.rb index 3235209c..e2d5656f 100644 --- a/controllers/wizard.rb +++ b/controllers/wizard.rb @@ -2,7 +2,6 @@ class CustomWizard::WizardController < ::ApplicationController prepend_view_path(Rails.root.join('plugins', 'discourse-custom-wizard', 'views')) layout 'wizard' - requires_login helper_method :wizard_page_title helper_method :theme_ids @@ -22,12 +21,11 @@ class CustomWizard::WizardController < ::ApplicationController respond_to do |format| format.json do builder = CustomWizard::Builder.new(current_user, params[:wizard_id].underscore) - builder_opts = {} builder_opts[:reset] = params[:reset] if params[:reset] if builder.wizard.present? - wizard = builder.build(builder_opts) + wizard = builder.build(builder_opts, params) render_serialized(wizard, WizardSerializer) else render json: { error: I18n.t('wizard.none') } @@ -52,19 +50,22 @@ class CustomWizard::WizardController < ::ApplicationController end result = success_json - submission = Array.wrap(PluginStore.get("#{wizard_id}_submissions", user.id)).last - if submission && submission['redirect_to'] - result.merge!(redirect_to: submission['redirect_to']) - end + if user + submission = Array.wrap(PluginStore.get("#{wizard_id}_submissions", user.id)).last - if submission && !wizard.save_submissions - PluginStore.remove("#{wizard_id}_submissions", user.id) - end + if submission && submission['redirect_to'] + result.merge!(redirect_to: submission['redirect_to']) + end - if user.custom_fields['redirect_to_wizard'] === wizard_id - user.custom_fields.delete('redirect_to_wizard') - user.save_custom_fields(true) + if submission && !wizard.save_submissions + PluginStore.remove("#{wizard_id}_submissions", user.id) + end + + if user.custom_fields['redirect_to_wizard'] === wizard_id + user.custom_fields.delete('redirect_to_wizard') + user.save_custom_fields(true) + end end render json: result diff --git a/lib/builder.rb b/lib/builder.rb index c2be9282..8533c4c3 100644 --- a/lib/builder.rb +++ b/lib/builder.rb @@ -2,14 +2,16 @@ class CustomWizard::Builder attr_accessor :wizard, :updater, :submissions - def initialize(user, wizard_id) + def initialize(user=nil, wizard_id) data = PluginStore.get('custom_wizard', wizard_id) - return if data.blank? @steps = data['steps'] @wizard = CustomWizard::Wizard.new(user, data) - @submissions = Array.wrap(PluginStore.get("#{wizard_id}_submissions", user.id)) + + if user + @submissions = Array.wrap(PluginStore.get("#{wizard_id}_submissions", user.id)) + end end def self.sorted_handlers @@ -49,10 +51,10 @@ class CustomWizard::Builder result end - result.gsub(/w\{(.*?)\}/) { |match| data[$1.to_sym] } + result = result.gsub(/w\{(.*?)\}/) { |match| data[$1.to_sym] } end - def build(build_opts = {}) + def build(build_opts = {}, params = {}) unless (@wizard.completed? && !@wizard.multiple_submissions && !@wizard.user.admin) || !@steps || !@wizard.permitted? reset_submissions if build_opts[:reset] @@ -63,6 +65,36 @@ class CustomWizard::Builder step.description = step_template['description'] if step_template['description'] step.banner = step_template['banner'] if step_template['banner'] step.key = step_template['key'] if step_template['key'] + step.permitted = true + + if permitted_params = step_template['permitted_params'] + permitted_data = {} + + permitted_params.each do |param| + key = param['key'].to_sym + permitted_data[key] = params[key] if params[key] + end + + if permitted_data.present? + current_data = @submissions.last || {} + save_submissions(current_data.merge(permitted_data), false) + end + end + + if required_data = step_template['required_data'] + if !@submissions.last && required_data.length + step.permitted = false + next + end + + required_data.each do |rd| + if rd['connector'] === 'equals' + step.permitted = @submissions.last[rd['key']] == @submissions.last[rd['value']] + end + end + + next if !step.permitted + end if step_template['fields'] && step_template['fields'].length step_template['fields'].each do |field_template| @@ -118,8 +150,13 @@ class CustomWizard::Builder end if updater.errors.empty? - redirect_to = data['redirect_to'] - updater.result = { redirect_to: redirect_to } if redirect_to + if route_to = data['route_to'] + updater.result[:route_to] = route_to + end + + if redirect_on_complete = data['redirect_on_complete'] + updater.result[:redirect_on_complete] = redirect_on_complete + end end end end @@ -200,9 +237,14 @@ class CustomWizard::Builder end elsif field_template['choices_preset'] && field_template['choices_preset'].length > 0 objects = [] + site = Site.new(Guardian.new(@wizard.user)) if field_template['choices_preset'] === 'categories' - objects = Site.new(Guardian.new(@wizard.user)).categories + objects = site.categories + end + + if field_template['choices_preset'] === 'groups' + objects = site.groups end if field_template['choices_filters'] && field_template['choices_filters'].length > 0 @@ -227,7 +269,11 @@ class CustomWizard::Builder def validate_field(field, updater, step_template) value = updater.fields[field['id']] - min_length = field['min_length'] + min_length = false + + if is_text_type(field) + min_length = field['min_length'] + end if min_length && value.is_a?(String) && value.strip.length < min_length.to_i label = field['label'] || I18n.t("#{field['key']}.label") @@ -246,6 +292,10 @@ class CustomWizard::Builder end end + def is_text_type(field) + ['text', 'textarea'].include? field['type'] + end + def standardise_boolean(value) !!HasCustomFields::Helpers::CUSTOM_FIELD_TRUE.include?(value) end @@ -309,6 +359,7 @@ class CustomWizard::Builder end end else + value = [value] if key === 'tags' params[key.to_sym] = value end end @@ -329,7 +380,7 @@ class CustomWizard::Builder end unless action['skip_redirect'] - data['redirect_to'] = post.topic.url + data['redirect_on_complete'] = post.topic.url end end end @@ -358,7 +409,7 @@ class CustomWizard::Builder updater.errors.add(:send_message, creator.errors.full_messages.join(" ")) else unless action['skip_redirect'] - data['redirect_to'] = post.topic.url + data['redirect_on_complete'] = post.topic.url end end end @@ -394,7 +445,6 @@ class CustomWizard::Builder end def send_to_api(user, action, data) - api_body = nil if action['api_body'] != "" @@ -415,6 +465,23 @@ class CustomWizard::Builder ## add validation callback end end + + def add_to_group(user, action, data) + if group_id = data[action['group_id']] + if group = Group.find(group_id) + group.add(user) + end + end + end + + def route_to(user, action, data) + url = CustomWizard::Builder.fill_placeholders(action['url'], user, data) + if action['code'] + data[action['code']] = SecureRandom.hex(8) + url += "&#{action['code']}=#{data[action['code']]}" + end + data['route_to'] = URI.encode(url) + end def save_submissions(data, final_step) if final_step diff --git a/lib/step_updater.rb b/lib/step_updater.rb index f267db9d..c521924c 100644 --- a/lib/step_updater.rb +++ b/lib/step_updater.rb @@ -9,6 +9,7 @@ class CustomWizard::StepUpdater @step = step @refresh_required = false @fields = fields + @result = {} end def update diff --git a/lib/wizard.rb b/lib/wizard.rb index e98b933a..b47d68f1 100644 --- a/lib/wizard.rb +++ b/lib/wizard.rb @@ -18,7 +18,7 @@ class CustomWizard::Wizard :required, :prompt_completion - def initialize(user, attrs = {}) + def initialize(user=nil, attrs = {}) @steps = [] @user = user @first_step = nil @@ -54,6 +54,8 @@ class CustomWizard::Wizard end def start + return nil if !@user + if unfinished? && last_completed_step = ::UserHistory.where( acting_user_id: @user.id, action: ::UserHistory.actions[:custom_wizard_step], @@ -76,6 +78,8 @@ class CustomWizard::Wizard end def unfinished? + return nil if !@user + most_recent = ::UserHistory.where( acting_user_id: @user.id, action: ::UserHistory.actions[:custom_wizard_step], @@ -94,6 +98,8 @@ class CustomWizard::Wizard end def completed? + return nil if !@user + steps = CustomWizard::Wizard.step_ids(@id) history = ::UserHistory.where( @@ -112,7 +118,7 @@ class CustomWizard::Wizard end def permitted? - user.staff? || user.trust_level.to_i >= min_trust.to_i + user && (user.staff? || user.trust_level.to_i >= min_trust.to_i) end def reset diff --git a/lib/wizard_edits.rb b/lib/wizard_edits.rb index 4a24afd3..dfab138a 100644 --- a/lib/wizard_edits.rb +++ b/lib/wizard_edits.rb @@ -60,11 +60,11 @@ end end class ::Wizard::Step - attr_accessor :title, :description, :key + attr_accessor :title, :description, :key, :permitted end ::WizardSerializer.class_eval do - attributes :id, :background, :completed, :required, :min_trust, :permitted + attributes :id, :name, :background, :completed, :required, :min_trust, :permitted, :user def id object.id @@ -74,6 +74,10 @@ end object.respond_to?(:id) end + def name + object.name + end + def background object.background end @@ -123,18 +127,28 @@ end def include_required? object.respond_to?(:required) end + + def user + object.user + end end ::WizardStepSerializer.class_eval do + attributes :permitted + def title - return object.title if object.title - I18n.t("#{object.key || i18n_key}.title", default: '') + 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 end ::WizardFieldSerializer.class_eval do