diff --git a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 index 8a2147b1..8a0f39e8 100644 --- a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 @@ -4,7 +4,8 @@ const ACTION_TYPES = [ { id: 'create_topic', name: 'Create Topic' }, { id: 'update_profile', name: 'Update Profile' }, { id: 'send_message', name: 'Send Message' }, - { id: 'add_to_group', name: 'Add to Group' } + { id: 'add_to_group', name: 'Add to Group' }, + { id: 'route_to', name: 'Route To' } ]; const PROFILE_FIELDS = [ @@ -28,33 +29,9 @@ export default Ember.Component.extend({ updateProfile: Ember.computed.equal('action.type', 'update_profile'), sendMessage: Ember.computed.equal('action.type', 'send_message'), 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-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..796acce5 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: "Route To Code" + })); + } + }); + + 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 34248250..3141afc2 100644 --- a/assets/javascripts/discourse/models/custom-wizard.js.es6 +++ b/assets/javascripts/discourse/models/custom-wizard.js.es6 @@ -76,6 +76,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) { @@ -231,6 +233,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 5cc5685e..4ef128c0 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs @@ -226,3 +226,22 @@ {{/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/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/models/custom.js.es6 b/assets/javascripts/wizard/models/custom.js.es6 index 089d12c8..4d12b169 100644 --- a/assets/javascripts/wizard/models/custom.js.es6 +++ b/assets/javascripts/wizard/models/custom.js.es6 @@ -24,16 +24,30 @@ 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; 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 0fd8e627..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/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_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 10efb43a..1ff397f9 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; + } } } @@ -169,13 +174,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; @@ -189,6 +199,10 @@ margin: 0 auto; align-self: flex-start; } + + .connector { + margin: 0 10px; + } } .setting .add-custom-input { @@ -299,5 +313,5 @@ } .wizard-step-contents{ - height: unset !important; + height: unset !important; } diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 5463f94a..194e1428 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -71,6 +71,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" @@ -127,6 +137,10 @@ en: 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" diff --git a/controllers/wizard.rb b/controllers/wizard.rb index e9e08637..e2d5656f 100644 --- a/controllers/wizard.rb +++ b/controllers/wizard.rb @@ -25,7 +25,7 @@ class CustomWizard::WizardController < ::ApplicationController 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') } diff --git a/lib/builder.rb b/lib/builder.rb index 542a3f8b..45b191b4 100644 --- a/lib/builder.rb +++ b/lib/builder.rb @@ -51,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] @@ -65,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| @@ -120,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 @@ -345,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 @@ -374,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 @@ -410,16 +445,22 @@ class CustomWizard::Builder end def add_to_group(user, action, data) - puts "GROUP NAME: #{data[action['group_id']]}" if group_id = data[action['group_id']] - puts "GROUP: #{Group.find(group_id)}" if group = Group.find(group_id) - puts "HERE IS THE GROUP: #{group.inspect}" 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 data['submitted_at'] = Time.now.iso8601 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_edits.rb b/lib/wizard_edits.rb index ad4f8ef7..dfab138a 100644 --- a/lib/wizard_edits.rb +++ b/lib/wizard_edits.rb @@ -60,7 +60,7 @@ end end class ::Wizard::Step - attr_accessor :title, :description, :key + attr_accessor :title, :description, :key, :permitted end ::WizardSerializer.class_eval do @@ -134,6 +134,8 @@ end end ::WizardStepSerializer.class_eval do + attributes :permitted + def title return PrettyText.cook(object.title) if object.title PrettyText.cook(I18n.t("#{object.key || i18n_key}.title", default: '')) @@ -143,6 +145,10 @@ end 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