diff --git a/assets/javascripts/discourse/components/custom-field-input.js.es6 b/assets/javascripts/discourse/components/custom-field-input.js.es6 index 877b83fb..a673112b 100644 --- a/assets/javascripts/discourse/components/custom-field-input.js.es6 +++ b/assets/javascripts/discourse/components/custom-field-input.js.es6 @@ -6,20 +6,20 @@ import I18n from "I18n"; const klasses = ["topic", "post", "group", "category"]; const types = ["string", "boolean", "integer", "json"]; -const proTypes = { +const subscriptionTypes = { klass: ["group", "category"], type: ["json"], }; -const generateContent = function (array, type, proSubscribed = false) { +const generateContent = function (array, type, subscribed = false) { return array.reduce((result, key) => { - let proArr = proTypes[type]; - let pro = proArr && proArr.includes(key); - if (!pro || proSubscribed) { + let subArr = subscriptionTypes[type]; + let subscription = subArr && subArr.includes(key); + if (!subscription || subscribed) { result.push({ id: key, name: I18n.t(`admin.wizard.custom_field.${type}.${key}`), - pro, + subscription, }); } return result; @@ -32,11 +32,11 @@ export default Component.extend({ postSerializers: ["post"], groupSerializers: ["basic_group"], categorySerializers: ["basic_category"], - klassContent: computed("proSubscribed", function () { - return generateContent(klasses, "klass", this.proSubscribed); + klassContent: computed("subscribed", function () { + return generateContent(klasses, "klass", this.subscribed); }), - typeContent: computed("proSubscribed", function () { - return generateContent(types, "type", this.proSubscribed); + typeContent: computed("subscribed", function () { + return generateContent(types, "type", this.subscribed); }), showInputs: or("field.new", "field.edit"), classNames: ["custom-field-input"], @@ -54,7 +54,7 @@ export default Component.extend({ const serializers = this.get(`${klass}Serializers`); if (serializers) { - return generateContent(serializers, "serializers", this.proSubscribed); + return generateContent(serializers, "serializers", this.subscribed); } else { return []; } diff --git a/assets/javascripts/discourse/components/subscription-container.js.es6 b/assets/javascripts/discourse/components/subscription-container.js.es6 new file mode 100644 index 00000000..08498f6f --- /dev/null +++ b/assets/javascripts/discourse/components/subscription-container.js.es6 @@ -0,0 +1,21 @@ +import Component from "@ember/component"; +import discourseComputed from "discourse-common/utils/decorators"; + +export default Component.extend({ + classNameBindings: [":subscription-container", "subscribed"], + + @discourseComputed('subscribed') + subscribedIcon(subscribed) { + return subscribed ? 'check' : 'dash'; + }, + + @discourseComputed('subscribed') + subscribedLabel(subscribed) { + return `admin.wizard.subscription_container.${subscribed ? 'subscribed' : 'not_subscribed'}.label`; + }, + + @discourseComputed('subscribed') + subscribedTitle(subscribed) { + return `admin.wizard.subscription_container.${subscribed ? 'subscribed' : 'not_subscribed'}.title`; + } +}) \ 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 c50be2ba..ffe5b514 100644 --- a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 @@ -94,15 +94,15 @@ export default Component.extend(UndoChanges, { return apis.find((a) => a.name === api).endpoints; }, - @discourseComputed("proSubscribed") - actionTypes(proSubscribed) { + @discourseComputed("subscribed") + actionTypes(subscribed) { return Object.keys(wizardSchema.action.types).reduce((result, type) => { - let pro = wizardSchema.action.proTypes.includes(type); - if (proSubscribed || !pro) { + let subscription = wizardSchema.action.subscriptionTypes.includes(type); + if (subscribed || !subscription) { result.push({ id: type, name: I18n.t(`admin.wizard.action.${type}.label`), - pro, + subscription, }); } return result; diff --git a/assets/javascripts/discourse/components/wizard-notice.js.es6 b/assets/javascripts/discourse/components/wizard-notice.js.es6 new file mode 100644 index 00000000..86a82c94 --- /dev/null +++ b/assets/javascripts/discourse/components/wizard-notice.js.es6 @@ -0,0 +1,34 @@ +import Component from "@ember/component"; +import discourseComputed from "discourse-common/utils/decorators"; +import { notEmpty, not } from "@ember/object/computed"; +import I18n from "I18n"; + +export default Component.extend({ + classNameBindings: [':wizard-notice', 'notice.type', 'dismissed', 'expired'], + showFull: false, + resolved: notEmpty('notice.expired_at'), + dismissed: notEmpty('notice.dismissed_at'), + canDismiss: not('dismissed'), + + @discourseComputed('notice.type') + title(type) { + return I18n.t(`admin.wizard.notice.title.${type}`); + }, + + @discourseComputed('notice.type') + icon(type) { + return { + warning: 'exclamation-circle', + info: 'info-circle' + }[type]; + }, + + actions: { + dismiss() { + this.set('dismissing', true) + this.notice.dismiss().then(() => { + this.set('dismissing', false); + }); + } + } +}); \ No newline at end of file diff --git a/assets/javascripts/discourse/components/wizard-realtime-validations.js.es6 b/assets/javascripts/discourse/components/wizard-realtime-validations.js.es6 index 04123e3d..b1d8a0f5 100644 --- a/assets/javascripts/discourse/components/wizard-realtime-validations.js.es6 +++ b/assets/javascripts/discourse/components/wizard-realtime-validations.js.es6 @@ -6,7 +6,7 @@ import discourseComputed from "discourse-common/utils/decorators"; import I18n from "I18n"; export default Component.extend({ - classNames: ["realtime-validations", "setting", "full", "pro"], + classNames: ["realtime-validations", "setting", "full", "subscription"], @discourseComputed timeUnits() { diff --git a/assets/javascripts/discourse/components/wizard-pro-selector.js.es6 b/assets/javascripts/discourse/components/wizard-subscription-selector.js.es6 similarity index 58% rename from assets/javascripts/discourse/components/wizard-pro-selector.js.es6 rename to assets/javascripts/discourse/components/wizard-subscription-selector.js.es6 index 8e472782..ec94bce5 100644 --- a/assets/javascripts/discourse/components/wizard-pro-selector.js.es6 +++ b/assets/javascripts/discourse/components/wizard-subscription-selector.js.es6 @@ -1,18 +1,18 @@ import SingleSelectComponent from "select-kit/components/single-select"; export default SingleSelectComponent.extend({ - classNames: ["combo-box", "wizard-pro-selector"], + classNames: ["combo-box", "wizard-subscription-selector"], selectKitOptions: { autoFilterable: false, filterable: false, showFullTitle: true, - headerComponent: "wizard-pro-selector/wizard-pro-selector-header", + headerComponent: "wizard-subscription-selector/wizard-subscription-selector-header", caretUpIcon: "caret-up", caretDownIcon: "caret-down", }, modifyComponentForRow() { - return "wizard-pro-selector/wizard-pro-selector-row"; + return "wizard-subscription-selector/wizard-subscription-selector-row"; }, }); diff --git a/assets/javascripts/discourse/components/wizard-pro-selector/wizard-pro-selector-header.js.es6 b/assets/javascripts/discourse/components/wizard-subscription-selector/wizard-subscription-selector-header.js.es6 similarity index 88% rename from assets/javascripts/discourse/components/wizard-pro-selector/wizard-pro-selector-header.js.es6 rename to assets/javascripts/discourse/components/wizard-subscription-selector/wizard-subscription-selector-header.js.es6 index c1f7251c..74f29f08 100644 --- a/assets/javascripts/discourse/components/wizard-pro-selector/wizard-pro-selector-header.js.es6 +++ b/assets/javascripts/discourse/components/wizard-subscription-selector/wizard-subscription-selector-header.js.es6 @@ -3,7 +3,7 @@ import { computed } from "@ember/object"; import { reads } from "@ember/object/computed"; export default SingleSelectHeaderComponent.extend({ - classNames: ["combo-box-header", "wizard-pro-selector-header"], + classNames: ["combo-box-header", "wizard-subscription-selector-header"], caretUpIcon: reads("selectKit.options.caretUpIcon"), caretDownIcon: reads("selectKit.options.caretDownIcon"), caretIcon: computed( diff --git a/assets/javascripts/discourse/components/wizard-pro-selector/wizard-pro-selector-row.js.es6 b/assets/javascripts/discourse/components/wizard-subscription-selector/wizard-subscription-selector-row.js.es6 similarity index 100% rename from assets/javascripts/discourse/components/wizard-pro-selector/wizard-pro-selector-row.js.es6 rename to assets/javascripts/discourse/components/wizard-subscription-selector/wizard-subscription-selector-row.js.es6 diff --git a/assets/javascripts/discourse/components/wizard-pro-subscription.js.es6 b/assets/javascripts/discourse/components/wizard-subscription.js.es6 similarity index 75% rename from assets/javascripts/discourse/components/wizard-pro-subscription.js.es6 rename to assets/javascripts/discourse/components/wizard-subscription.js.es6 index 7824cb83..0d839a5f 100644 --- a/assets/javascripts/discourse/components/wizard-pro-subscription.js.es6 +++ b/assets/javascripts/discourse/components/wizard-subscription.js.es6 @@ -1,12 +1,12 @@ import Component from "@ember/component"; -import CustomWizardPro from "../models/custom-wizard-pro"; +import CustomWizardSubscription from "../models/custom-wizard-subscription"; import { notEmpty } from "@ember/object/computed"; import discourseComputed from "discourse-common/utils/decorators"; import I18n from "I18n"; export default Component.extend({ classNameBindings: [ - ":custom-wizard-pro-subscription", + ":custom-wizard-subscription", "subscription.active:active:inactive", ], subscribed: notEmpty("subscription"), @@ -14,8 +14,8 @@ export default Component.extend({ @discourseComputed("subscription.type") title(type) { return type - ? I18n.t(`admin.wizard.pro.subscription.title.${type}`) - : I18n.t("admin.wizard.pro.not_subscribed"); + ? I18n.t(`admin.wizard.subscription.subscription.title.${type}`) + : I18n.t("admin.wizard.subscription.not_subscribed"); }, @discourseComputed("subscription.active") @@ -25,13 +25,13 @@ export default Component.extend({ @discourseComputed("stateClass") stateLabel(stateClass) { - return I18n.t(`admin.wizard.pro.subscription.status.${stateClass}`); + return I18n.t(`admin.wizard.subscription.subscription.status.${stateClass}`); }, actions: { update() { this.set("updating", true); - CustomWizardPro.update_subscription() + CustomWizardSubscription.update() .then((result) => { if (result.success) { this.setProperties({ diff --git a/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-issue-notice.hbs b/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-issue-notice.hbs new file mode 100644 index 00000000..a8aad815 --- /dev/null +++ b/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-issue-notice.hbs @@ -0,0 +1,3 @@ +{{#if wizardWarningNotice}} + {{wizard-notice notice=wizardWarningNotice}} +{{/if}} \ No newline at end of file diff --git a/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-issue-notice.js.es6 b/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-issue-notice.js.es6 new file mode 100644 index 00000000..b92e7897 --- /dev/null +++ b/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-issue-notice.js.es6 @@ -0,0 +1,12 @@ +import { getOwner } from "discourse-common/lib/get-owner"; + +export default { + setupComponent() { + const controller = getOwner(this).lookup('controller:admin-dashboard') + const wizardWarningNotice = controller.get('wizardWarningNotice'); + + if (wizardWarningNotice) { + this.set('wizardWarningNotice', wizardWarningNotice); + } + } +} \ No newline at end of file diff --git a/assets/javascripts/discourse/connectors/admin-menu/wizards-nav-button.hbs b/assets/javascripts/discourse/connectors/admin-menu/wizards-nav-button.hbs index f76722fc..f893d4ac 100644 --- a/assets/javascripts/discourse/connectors/admin-menu/wizards-nav-button.hbs +++ b/assets/javascripts/discourse/connectors/admin-menu/wizards-nav-button.hbs @@ -1,3 +1,7 @@ {{#if currentUser.admin}} {{nav-item route="adminWizards" label="admin.wizard.nav_label"}} + + {{#if wizardErrorNotice}} + {{d-icon "exclaimation-circle"}} + {{/if}} {{/if}} diff --git a/assets/javascripts/discourse/controllers/admin-wizards-pro.js.es6 b/assets/javascripts/discourse/controllers/admin-wizards-subscription.js.es6 similarity index 95% rename from assets/javascripts/discourse/controllers/admin-wizards-pro.js.es6 rename to assets/javascripts/discourse/controllers/admin-wizards-subscription.js.es6 index 61012d8f..844d5a25 100644 --- a/assets/javascripts/discourse/controllers/admin-wizards-pro.js.es6 +++ b/assets/javascripts/discourse/controllers/admin-wizards-subscription.js.es6 @@ -1,6 +1,6 @@ import Controller from "@ember/controller"; import discourseComputed from "discourse-common/utils/decorators"; -import CustomWizardPro from "../models/custom-wizard-pro"; +import CustomWizardSubscription from "../models/custom-wizard-subscription"; import { alias } from "@ember/object/computed"; export default Controller.extend({ diff --git a/assets/javascripts/discourse/controllers/admin-wizards.js.es6 b/assets/javascripts/discourse/controllers/admin-wizards.js.es6 new file mode 100644 index 00000000..a94222c1 --- /dev/null +++ b/assets/javascripts/discourse/controllers/admin-wizards.js.es6 @@ -0,0 +1,20 @@ +import Controller from "@ember/controller"; +import { popupAjaxError } from "discourse/lib/ajax-error"; +import { ajax } from "discourse/lib/ajax"; + +export default Controller.extend({ + actions: { + dismissNotice(noticeId) { + ajax(`/admin/wizards/notice/${this.id}`, { + type: "DELETE", + }) + .then(result => { + if (result.success) { + const notices = this.notices; + notices.removeObject(notices.findBy('id', noticeId)); + } + }) + .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 1ca6d41b..67b91f87 100644 --- a/assets/javascripts/discourse/custom-wizard-admin-route-map.js.es6 +++ b/assets/javascripts/discourse/custom-wizard-admin-route-map.js.es6 @@ -59,8 +59,8 @@ export default { resetNamespace: true, }); - this.route("adminWizardsPro", { - path: "/pro", + this.route("adminWizardsSubscription", { + path: "/subscription", resetNamespace: true, }); } diff --git a/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6 b/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6 index 63ddd5e8..4bf50fa9 100644 --- a/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6 +++ b/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6 @@ -1,4 +1,8 @@ import DiscourseURL from "discourse/lib/url"; +import { withPluginApi } from "discourse/lib/plugin-api"; +import { ajax } from "discourse/lib/ajax"; +import CustomWizardNotice from "../models/custom-wizard-notice"; +import { A } from "@ember/array"; export default { name: "custom-wizard-edits", @@ -16,5 +20,29 @@ export default { } return existing.apply(this, [path, opts]); }; + + withPluginApi("0.8.36", (api) => { + api.modifyClass('route:admin-dashboard', { + afterModel() { + return CustomWizardNotice.list().then(result => { + if (result && result.length) { + this.set('notices', A(result.map(n => CustomWizardNotice.create(n)))); + } + }); + }, + + setupController(controller, model) { + if (this.notices) { + let warningNotices = this.notices.filter(n => n.type === 'warning'); + + if (warningNotices.length) { + controller.set('wizardWarningNotice', warningNotices[0]); + } + } + + this._super(...arguments); + } + }); + }); }, }; diff --git a/assets/javascripts/discourse/lib/wizard-schema.js.es6 b/assets/javascripts/discourse/lib/wizard-schema.js.es6 index a20b61a7..5d876ed0 100644 --- a/assets/javascripts/discourse/lib/wizard-schema.js.es6 +++ b/assets/javascripts/discourse/lib/wizard-schema.js.es6 @@ -193,6 +193,14 @@ const action = { "members_visibility_level", ], required: ["id", "type"], + subscriptionTypes: [ + "send_message", + "add_to_group", + "create_category", + "create_group", + "send_to_api", + ], + required: ["id", "type"], proTypes: [ "send_message", "add_to_group", diff --git a/assets/javascripts/discourse/models/custom-wizard-notice.js.es6 b/assets/javascripts/discourse/models/custom-wizard-notice.js.es6 new file mode 100644 index 00000000..bae81822 --- /dev/null +++ b/assets/javascripts/discourse/models/custom-wizard-notice.js.es6 @@ -0,0 +1,23 @@ +import EmberObject from "@ember/object"; +import { ajax } from "discourse/lib/ajax"; +import { popupAjaxError } from "discourse/lib/ajax-error"; + +const CustomWizardNotice = EmberObject.extend(); + +CustomWizardNotice.reopen({ + dismiss() { + return ajax(`/admin/wizards/notice/${this.id}`, { type: 'PUT' }).then(result => { + if (result.success) { + this.set('dismissed_at', result.dismissed_at); + } + }).catch(popupAjaxError) + } +}); + +CustomWizardNotice.reopenClass({ + list() { + return ajax('/admin/wizards/notice').catch(popupAjaxError) + } +}); + +export default CustomWizardNotice; \ No newline at end of file diff --git a/assets/javascripts/discourse/models/custom-wizard-pro.js.es6 b/assets/javascripts/discourse/models/custom-wizard-subscription.js.es6 similarity index 68% rename from assets/javascripts/discourse/models/custom-wizard-pro.js.es6 rename to assets/javascripts/discourse/models/custom-wizard-subscription.js.es6 index 76429726..469460d5 100644 --- a/assets/javascripts/discourse/models/custom-wizard-pro.js.es6 +++ b/assets/javascripts/discourse/models/custom-wizard-subscription.js.es6 @@ -2,11 +2,11 @@ import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; import EmberObject from "@ember/object"; -const CustomWizardPro = EmberObject.extend(); +const CustomWizardSubscription = EmberObject.extend(); -const basePath = "/admin/wizards/pro"; +const basePath = "/admin/wizards/subscription"; -CustomWizardPro.reopenClass({ +CustomWizardSubscription.reopenClass({ status() { return ajax(basePath, { type: "GET", @@ -23,11 +23,11 @@ CustomWizardPro.reopenClass({ }).catch(popupAjaxError); }, - update_subscription() { - return ajax(`${basePath}/subscription`, { + update() { + return ajax(basePath, { type: "POST", }).catch(popupAjaxError); }, }); -export default CustomWizardPro; +export default CustomWizardSubscription; diff --git a/assets/javascripts/discourse/routes/admin-wizards-custom-fields.js.es6 b/assets/javascripts/discourse/routes/admin-wizards-custom-fields.js.es6 index 45ca9ae7..ca9c4c40 100644 --- a/assets/javascripts/discourse/routes/admin-wizards-custom-fields.js.es6 +++ b/assets/javascripts/discourse/routes/admin-wizards-custom-fields.js.es6 @@ -9,11 +9,11 @@ export default DiscourseRoute.extend({ setupController(controller, model) { const customFields = A(model.custom_fields || []); - const proSubscribed = model.pro_subscribed; + const subscribed = model.subscribed; controller.setProperties({ customFields, - proSubscribed, + subscribed, }); }, }); diff --git a/assets/javascripts/discourse/routes/admin-wizards-pro.js.es6 b/assets/javascripts/discourse/routes/admin-wizards-subscription.js.es6 similarity index 61% rename from assets/javascripts/discourse/routes/admin-wizards-pro.js.es6 rename to assets/javascripts/discourse/routes/admin-wizards-subscription.js.es6 index d5c7fbd7..4824425a 100644 --- a/assets/javascripts/discourse/routes/admin-wizards-pro.js.es6 +++ b/assets/javascripts/discourse/routes/admin-wizards-subscription.js.es6 @@ -1,9 +1,9 @@ -import CustomWizardPro from "../models/custom-wizard-pro"; +import CustomWizardSubscription from "../models/custom-wizard-subscription"; import DiscourseRoute from "discourse/routes/discourse"; export default DiscourseRoute.extend({ model() { - return CustomWizardPro.status(); + return CustomWizardSubscription.status(); }, setupController(controller, model) { @@ -13,7 +13,7 @@ export default DiscourseRoute.extend({ actions: { authorize() { - CustomWizardPro.authorize(); + CustomWizardSubscription.authorize(); }, }, }); 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 7032b974..046fc6d4 100644 --- a/assets/javascripts/discourse/routes/admin-wizards-wizard-show.js.es6 +++ b/assets/javascripts/discourse/routes/admin-wizards-wizard-show.js.es6 @@ -39,7 +39,7 @@ export default DiscourseRoute.extend({ currentStep: wizard.steps[0], currentAction: wizard.actions[0], creating: model.create, - proSubscribed: parentModel.pro_subscribed, + subscribed: parentModel.subscribed, }; controller.setProperties(props); diff --git a/assets/javascripts/discourse/routes/admin-wizards.js.es6 b/assets/javascripts/discourse/routes/admin-wizards.js.es6 index 5de271a8..da184d93 100644 --- a/assets/javascripts/discourse/routes/admin-wizards.js.es6 +++ b/assets/javascripts/discourse/routes/admin-wizards.js.es6 @@ -1,9 +1,19 @@ import DiscourseRoute from "discourse/routes/discourse"; +import { ajax } from "discourse/lib/ajax"; +import { A } from "@ember/array"; export default DiscourseRoute.extend({ - beforeModel(transition) { + model() { + return ajax('/admin/wizards'); + }, + + setupController(controller, model) { + controller.set('notices', A(model.notices)); + }, + + afterModel(model, transition) { if (transition.targetName === "adminWizards.index") { this.transitionTo("adminWizardsWizard"); } - }, + } }); diff --git a/assets/javascripts/discourse/templates/admin-wizards-custom-fields.hbs b/assets/javascripts/discourse/templates/admin-wizards-custom-fields.hbs index 09a0d569..361d2d44 100644 --- a/assets/javascripts/discourse/templates/admin-wizards-custom-fields.hbs +++ b/assets/javascripts/discourse/templates/admin-wizards-custom-fields.hbs @@ -33,7 +33,7 @@ field=field removeField=(action "removeField") saveField=(action "saveField") - proSubscribed=proSubscribed}} + subscribed=subscribed}} {{/each}} diff --git a/assets/javascripts/discourse/templates/admin-wizards-pro.hbs b/assets/javascripts/discourse/templates/admin-wizards-pro.hbs deleted file mode 100644 index b4f0691b..00000000 --- a/assets/javascripts/discourse/templates/admin-wizards-pro.hbs +++ /dev/null @@ -1,34 +0,0 @@ -
-

{{i18n "admin.wizard.pro.title"}}

- -
- {{#if model.authentication.active}} - {{conditional-loading-spinner size="small" condition=unauthorizing}} - - {{i18n "admin.wizard.pro.unauthorize"}} - - - {{else}} - {{d-button - icon="id-card" - label="admin.wizard.pro.authorize" - title="admin.wizard.pro.authorize" - action=(route-action "authorize")}} - {{/if}} -
-
- -{{wizard-message - key=messageKey - url=messageUrl - type=messageType - opts=messageOpts - component="pro"}} - -
- {{#if showSubscription}} - {{wizard-pro-subscription subscription=model.subscription}} - {{/if}} -
diff --git a/assets/javascripts/discourse/templates/admin-wizards-subscription.hbs b/assets/javascripts/discourse/templates/admin-wizards-subscription.hbs new file mode 100644 index 00000000..c75f3e1b --- /dev/null +++ b/assets/javascripts/discourse/templates/admin-wizards-subscription.hbs @@ -0,0 +1,35 @@ +
+

{{i18n "admin.wizard.subscription.title"}}

+ +
+ {{#if model.authentication.active}} + {{conditional-loading-spinner size="small" condition=unauthorizing}} + + {{i18n "admin.wizard.subscription.unauthorize"}} + + + {{else}} + {{d-button + icon="id-card" + class="btn-primary" + label="admin.wizard.subscription.authorize" + title="admin.wizard.subscription.authorize" + action=(route-action "authorize")}} + {{/if}} +
+
+ +{{wizard-message + key=messageKey + url=messageUrl + type=messageType + opts=messageOpts + component="subscription"}} + +
+ {{#if showSubscription}} + {{wizard-subscription subscription=model.subscription}} + {{/if}} +
diff --git a/assets/javascripts/discourse/templates/admin-wizards-wizard-show.hbs b/assets/javascripts/discourse/templates/admin-wizards-wizard-show.hbs index 472cbfcb..3966a50c 100644 --- a/assets/javascripts/discourse/templates/admin-wizards-wizard-show.hbs +++ b/assets/javascripts/discourse/templates/admin-wizards-wizard-show.hbs @@ -126,11 +126,10 @@ - {{#if proSubscribed}} -
+ {{#subscription-container subscribed=subscribed}} +
- {{i18n "admin.wizard.pro.label"}}
{{input type="checkbox" checked=wizard.save_submissions}} @@ -138,17 +137,16 @@
-
+
- {{i18n "admin.wizard.pro.label"}}
{{input type="checkbox" checked=wizard.restart_on_revisit}} {{i18n "admin.wizard.restart_on_revisit_label"}}
- {{/if}} + {{/subscription-container}}
{{wizard-links @@ -163,7 +161,7 @@ currentField=currentField wizardFields=wizardFields fieldTypes=fieldTypes - proSubscribed=proSubscribed}} + subscribed=subscribed}} {{/if}} {{wizard-links @@ -180,7 +178,7 @@ apis=apis removeAction="removeAction" wizardFields=wizardFields - proSubscribed=proSubscribed}} + subscribed=subscribed}} {{/each}}
diff --git a/assets/javascripts/discourse/templates/admin-wizards.hbs b/assets/javascripts/discourse/templates/admin-wizards.hbs index 0578e01f..5ab666c7 100644 --- a/assets/javascripts/discourse/templates/admin-wizards.hbs +++ b/assets/javascripts/discourse/templates/admin-wizards.hbs @@ -7,13 +7,18 @@ {{/if}} {{nav-item route="adminWizardsLogs" label="admin.wizard.log.nav_label"}} {{nav-item route="adminWizardsManager" label="admin.wizard.manager.nav_label"}} - {{nav-item route="adminWizardsPro" label="admin.wizard.pro.nav_label"}} + {{nav-item route="adminWizardsSubscription" label="admin.wizard.subscription.nav_label"}} {{/admin-nav}}
+ {{#each notices as |notice|}} + {{wizard-notice notice=notice}} + {{/each}} {{outlet}}
diff --git a/assets/javascripts/discourse/templates/components/custom-field-input.hbs b/assets/javascripts/discourse/templates/components/custom-field-input.hbs index 2bb9acce..ac7e8689 100644 --- a/assets/javascripts/discourse/templates/components/custom-field-input.hbs +++ b/assets/javascripts/discourse/templates/components/custom-field-input.hbs @@ -1,13 +1,13 @@ {{#if showInputs}} - {{wizard-pro-selector + {{wizard-subscription-selector value=field.klass content=klassContent none="admin.wizard.custom_field.klass.select" onChange=(action (mut field.klass))}} - {{wizard-pro-selector + {{wizard-subscription-selector value=field.type content=typeContent none="admin.wizard.custom_field.type.select" diff --git a/assets/javascripts/discourse/templates/components/subscription-container.hbs b/assets/javascripts/discourse/templates/components/subscription-container.hbs new file mode 100644 index 00000000..7a02f555 --- /dev/null +++ b/assets/javascripts/discourse/templates/components/subscription-container.hbs @@ -0,0 +1,12 @@ +
+

{{i18n 'admin.wizard.subscription_container.title'}}

+ + + {{d-icon subscribedIcon}} + {{i18n subscribedLabel}} + +
+ +
+ {{yield}} +
\ 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 f5d53200..cb4cf28d 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs @@ -12,7 +12,7 @@
- {{wizard-pro-selector + {{wizard-subscription-selector value=action.type content=actionTypes onChange=(action "changeType") diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-field.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-field.hbs index fe3089ac..e271d0af 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-field.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-field.hbs @@ -207,11 +207,10 @@
{{/if}} -{{#if proSubscribed}} -
+{{#subscription-container subscribed=subscribed}} +
- {{i18n "admin.wizard.pro.label"}}
@@ -221,10 +220,9 @@
-
+
- - {{i18n "admin.wizard.pro.label"}} + >
@@ -256,4 +254,4 @@ {{#if validations}} {{wizard-realtime-validations field=field validations=validations}} {{/if}} -{{/if}} +{{/subscription-container}} diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-step.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-step.hbs index 3feb6731..320b5e47 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-step.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-step.hbs @@ -33,11 +33,10 @@
-{{#if proSubscribed}} -
+{{#subscription-container subscribed=subscribed}} +
- {{i18n "admin.wizard.pro.label"}}
@@ -83,10 +82,9 @@
-
+
- {{i18n "admin.wizard.pro.label"}}
{{wizard-mapper @@ -100,7 +98,7 @@ )}}
-{{/if}} +{{/subscription-container}} {{wizard-links itemType="field" @@ -116,5 +114,5 @@ fieldTypes=fieldTypes removeField="removeField" wizardFields=wizardFields - proSubscribed=proSubscribed}} + subscribed=subscribed}} {{/each}} diff --git a/assets/javascripts/discourse/templates/components/wizard-notice.hbs b/assets/javascripts/discourse/templates/components/wizard-notice.hbs new file mode 100644 index 00000000..f6f923a3 --- /dev/null +++ b/assets/javascripts/discourse/templates/components/wizard-notice.hbs @@ -0,0 +1,37 @@ +
+ {{#if resolved}} +
+ {{d-icon "check"}} + {{i18n "admin.wizard.notice.resolved"}} + {{format-date notice.expired_at leaveAgo="true"}} +
+ {{/if}} + +
+ {{d-icon icon}} + {{title}} +
+ +
+ {{d-icon "calendar-alt"}} + {{i18n "admin.wizard.notice.issued"}} + {{format-date notice.created_at leaveAgo="true"}} +
+ +
+ {{d-icon "plug"}} + {{i18n "admin.wizard.notice.plugin"}} +
+
+ +
+ {{{notice.message}}} +
+ +{{#if canDismiss}} + {{#if dismissing}} + {{loading-spinner size="small"}} + {{else}} + {{d-icon "times"}} + {{/if}} +{{/if}} \ No newline at end of file diff --git a/assets/javascripts/discourse/templates/components/wizard-realtime-validations.hbs b/assets/javascripts/discourse/templates/components/wizard-realtime-validations.hbs index 1aa0893b..8269d6ca 100644 --- a/assets/javascripts/discourse/templates/components/wizard-realtime-validations.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-realtime-validations.hbs @@ -1,6 +1,5 @@
- {{i18n "admin.wizard.pro.label"}}
    diff --git a/assets/javascripts/discourse/templates/components/wizard-pro-selector/wizard-pro-selector-header.hbs b/assets/javascripts/discourse/templates/components/wizard-subscription-selector/wizard-subscription-selector-header.hbs similarity index 70% rename from assets/javascripts/discourse/templates/components/wizard-pro-selector/wizard-pro-selector-header.hbs rename to assets/javascripts/discourse/templates/components/wizard-subscription-selector/wizard-subscription-selector-header.hbs index db467b02..a7e3d2e6 100644 --- a/assets/javascripts/discourse/templates/components/wizard-pro-selector/wizard-pro-selector-header.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-subscription-selector/wizard-subscription-selector-header.hbs @@ -7,8 +7,8 @@ shouldDisplayClearableButton=shouldDisplayClearableButton }} - {{#if selectedContent.pro}} - {{i18n "admin.wizard.pro.label"}} + {{#if selectedContent.subscription}} + {{i18n "admin.wizard.subscription.label"}} {{/if}} {{d-icon caretIcon class="caret-icon"}} diff --git a/assets/javascripts/discourse/templates/components/wizard-pro-selector/wizard-pro-selector-row.hbs b/assets/javascripts/discourse/templates/components/wizard-subscription-selector/wizard-subscription-selector-row.hbs similarity index 71% rename from assets/javascripts/discourse/templates/components/wizard-pro-selector/wizard-pro-selector-row.hbs rename to assets/javascripts/discourse/templates/components/wizard-subscription-selector/wizard-subscription-selector-row.hbs index 077265ef..e2650408 100644 --- a/assets/javascripts/discourse/templates/components/wizard-pro-selector/wizard-pro-selector-row.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-subscription-selector/wizard-subscription-selector-row.hbs @@ -9,7 +9,7 @@
    {{html-safe label}} - {{#if item.pro}} - {{i18n "admin.wizard.pro.label"}} + {{#if item.subscription}} + {{i18n "admin.wizard.subscription.label"}} {{/if}}
    diff --git a/assets/javascripts/discourse/templates/components/wizard-pro-subscription.hbs b/assets/javascripts/discourse/templates/components/wizard-subscription.hbs similarity index 72% rename from assets/javascripts/discourse/templates/components/wizard-pro-subscription.hbs rename to assets/javascripts/discourse/templates/components/wizard-subscription.hbs index 8eca5996..418225a3 100644 --- a/assets/javascripts/discourse/templates/components/wizard-pro-subscription.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-subscription.hbs @@ -13,8 +13,8 @@ icon="sync" action=(action "update") disabled=updating - title="admin.wizard.pro.subscription.update" - label="admin.wizard.pro.subscription.update"}} + title="admin.wizard.subscription.subscription.update" + label="admin.wizard.subscription.subscription.update"}}
@@ -24,7 +24,7 @@ {{#if subscription.updated_at}}
- {{i18n "admin.wizard.pro.subscription.last_updated"}} {{format-date subscription.updated_at leaveAgo="true"}} + {{i18n "admin.wizard.subscription.subscription.last_updated"}} {{format-date subscription.updated_at leaveAgo="true"}}
{{/if}}
diff --git a/assets/stylesheets/common/wizard-admin.scss b/assets/stylesheets/admin/admin.scss similarity index 86% rename from assets/stylesheets/common/wizard-admin.scss rename to assets/stylesheets/admin/admin.scss index 7c6cd95d..2eb32bf3 100644 --- a/assets/stylesheets/common/wizard-admin.scss +++ b/assets/stylesheets/admin/admin.scss @@ -1,8 +1,8 @@ -@import "wizard-mapper"; -@import "wizard-manager"; -@import "wizard-api"; +@import "wizard/mapper"; +@import "wizard/manager"; +@import "wizard/api"; @import "common/components/buttons"; -@import "wizard-variables"; +@import "wizard/variables"; .admin-wizard-controls { display: flex; @@ -121,7 +121,7 @@ } .wizard-settings-parent { - padding: 20px; + padding: 1em; border: 1px solid var(--primary-low); } @@ -142,7 +142,7 @@ .wizard-basic-details, .wizard-custom-field, -.advanced-settings { +.subscription-settings { @extend .wizard-settings-group; } @@ -411,7 +411,7 @@ margin-top: 5px; } - &.pro { + &.subscription { .setting-label { display: flex; flex-direction: column; @@ -423,15 +423,6 @@ } } - .advanced-settings { - width: 100%; - margin-top: 30px; - - [class~="setting"]:first-of-type { - border-top: none; - } - } - .wizard-custom-action > [class~="setting"]:first-of-type { margin-bottom: 0; } @@ -735,7 +726,7 @@ flex-wrap: wrap; > li { - background-color: var(--primary-low); + border: 1px solid var(--primary); padding: 1em; margin: 0 0 1em 0; @@ -797,12 +788,12 @@ vertical-align: middle; } -.pro-label { +.subscription-label { color: var(--tertiary); font-size: 0.75em; } -.admin-wizards-pro { +.admin-wizards-subscription { .admin-wizard-controls { h3, label { @@ -826,7 +817,7 @@ } } - .custom-wizard-pro-subscription { + .custom-wizard-subscription { .title-container { display: flex; justify-content: space-between; @@ -861,19 +852,19 @@ } } -.wizard-pro-selector.select-kit.single-select { +.wizard-subscription-selector.select-kit.single-select { .select-kit-row .texts { display: flex; align-items: center; } - .pro-label { + .subscription-label { margin-left: 0.75em; padding-top: 0.25em; } } -.btn.btn-pavilion-pro { +.btn.btn-pavilion-support { background: var(--pavilion-primary); color: var(--pavilion-secondary); @@ -883,11 +874,108 @@ &:hover, &:focus { - background: darken($pavilionPrimary, 5%); + background: darken($pavilion_primary, 5%); &[href], svg.d-icon { - color: darken($pavilionSecondary, 10%); + color: darken($pavilion_secondary, 10%); } } } + +.subscription-container { + width: 100%; + padding: 1em; + background-color: rgba($pavilion_primary, 0.1); + + .subscription-header { + display: flex; + justify-content: space-between; + margin-bottom: 1em; + + h3 { + margin: 0; + } + + a { + color: var(--pavilion-primary); + } + } + + &:not(.subscribed) .subscription-settings { + filter: blur(1px); + } +} + +.wizard-notice { + padding: 1em; + margin-bottom: 1em; + border: 1px solid var(--primary); + border-radius: 4px; + position: relative; + + &.dismissed { + display: none; + } + + .d-icon { + margin-right: .4em; + } + + .notice-header { + display: flex; + } + + .notice-badge { + border: 1px solid var(--primary); + display: inline-flex; + align-items: center; + padding: 0 .5em; + border-radius: 4px; + margin-right: 1em; + font-size: .9em; + line-height: 25px; + min-height: 25px; + box-sizing: border-box; + + &:last-of-type { + margin-right: 0; + } + } + + &.warning { + .notice-expired-at { + border: 1px solid var(--success); + background-color: rgba($success, 0.1); + color: var(--success); + } + + .notice-title { + border: 1px solid var(--pavilion-warning); + background-color: rgba($pavilion_warning, 0.1); + color: var(--pavilion-warning); + } + } + + .notice-issued { + margin-right: .3em; + } + + .notice-message { + p { + margin: .5em 0; + } + + p:last-of-type { + margin-bottom: 0; + } + } + + .dismiss-notice, + .spinner { + position: absolute; + top: 1em; + right: 1em; + color: var(--primary); + } +} diff --git a/assets/stylesheets/common/wizard-api.scss b/assets/stylesheets/admin/wizard/api.scss similarity index 100% rename from assets/stylesheets/common/wizard-api.scss rename to assets/stylesheets/admin/wizard/api.scss diff --git a/assets/stylesheets/common/wizard-manager.scss b/assets/stylesheets/admin/wizard/manager.scss similarity index 100% rename from assets/stylesheets/common/wizard-manager.scss rename to assets/stylesheets/admin/wizard/manager.scss diff --git a/assets/stylesheets/common/wizard-mapper.scss b/assets/stylesheets/admin/wizard/mapper.scss similarity index 100% rename from assets/stylesheets/common/wizard-mapper.scss rename to assets/stylesheets/admin/wizard/mapper.scss diff --git a/assets/stylesheets/admin/wizard/variables.scss b/assets/stylesheets/admin/wizard/variables.scss new file mode 100644 index 00000000..5912f961 --- /dev/null +++ b/assets/stylesheets/admin/wizard/variables.scss @@ -0,0 +1,9 @@ +$pavilion_primary: #3c1c8c; +$pavilion_secondary: #ffffff; +$pavilion_warning: rgb(243, 163, 61); + +:root { + --pavilion-primary: #{$pavilion_primary}; + --pavilion-secondary: #{$pavilion_secondary}; + --pavilion-warning: #{$pavilion_warning}; +} diff --git a/assets/stylesheets/common/wizard-variables.scss b/assets/stylesheets/common/wizard-variables.scss deleted file mode 100644 index 68f02b6b..00000000 --- a/assets/stylesheets/common/wizard-variables.scss +++ /dev/null @@ -1,7 +0,0 @@ -$pavilionPrimary: #3c1c8c; -$pavilionSecondary: #ffffff; - -:root { - --pavilion-primary: #3c1c8c; - --pavilion-secondary: #ffffff; -} diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 04b9ceab..a63677c6 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -60,9 +60,9 @@ en: expand_text: "Read More" collapse_text: "Show Less" - pro_support_button: - title: "Request Pro Support" - label: "Pro Support" + support_button: + title: "Request Support" + label: "Support" message: wizard: @@ -95,10 +95,10 @@ en: destroying: Destroying wizards... import_complete: Import complete destroy_complete: Destruction complete - pro: - documentation: Check out the PRO documentation - authorize: "Authorize this forum to use your PRO subscription plan on %{server}." - not_subscribed: "You've authorized, but are not currently subscribed to a PRO plan on %{server}." + subscription: + documentation: Check out the subscription documentation + authorize: "Authorize this forum to use your Custom Wizard subscription plan on %{server}." + not_subscribed: "You've authorized, but are not currently subscribed to a Custom Wizard plan on %{server}." subscription_expiring: "Your subscription is active, but will expire in the next 48 hours." subscription_active: "Your subscription is active." subscription_inactive: "Your subscription is inactive on this forum. Read more in the documentation." @@ -455,10 +455,19 @@ en: destroy: Destroy destroyed: destroyed - pro: - nav_label: PRO - label: PRO - title: Custom Wizard PRO + subscription_container: + title: Subscriber Features + subscribed: + label: Subscribed + title: You're subscribed and can use these features + not_subscribed: + label: Not Subscribed + title: Subscribe to use these features + + subscription: + nav_label: Subscription + label: Subscription + title: Custom Wizard Subscription authorize: Authorize authorized: Authorized unauthorize: cancel @@ -471,7 +480,14 @@ en: active: Active inactive: Inactive update: Update - last_updated: Last updated + last_updated: Last updated + + notice: + plugin: Custom Wizard Plugin + issued: Issued + resolved: Resolved + title: + warning: Warning Notice wizard_js: group: diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index fffa01cc..63996b02 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -17,7 +17,7 @@ en: name_too_short: "'%{name}' is too short for a custom field name (min length is #{min_length})" name_already_taken: "'%{name}' is already taken as a custom field name" save_default: "Failed to save custom field '%{name}'" - pro_type: "%{type} custom fields require PRO Subscription" + subscription_type: "%{type} custom fields require a subscription" field: too_short: "%{label} must be at least %{min} characters" @@ -50,7 +50,16 @@ en: required: "%{property} is required" conflict: "Wizard with id '%{wizard_id}' already exists" after_time: "After time setting is invalid" - pro: "%{type} %{property} is PRO only" + subscription: "%{type} %{property} is subscription only" + + notice: + connection_error: "Failed to connect to [%{server}](http://%{server})" + compatibility_issue: > + The Custom Wizard Plugin may have a compatibility issue with the latest version of Discourse. + Please check the Custom Wizard Plugin status on [%{server}](http://%{server}) before updating Discourse. + plugin_status_connection_error_limit: > + We're unable to connect to the plugin status server to determine whether there are any compatibility issues with the latest version of Discourse. + Please contact support@thepavilion.io for further assistance. site_settings: custom_wizard_enabled: "Enable custom wizards." diff --git a/config/routes.rb b/config/routes.rb index 3a37a137..0d59b200 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -45,10 +45,13 @@ Discourse::Application.routes.append do post 'admin/wizards/manager/import' => 'admin_manager#import' delete 'admin/wizards/manager/destroy' => 'admin_manager#destroy' - get 'admin/wizards/pro' => 'admin_pro#index' - get 'admin/wizards/pro/authorize' => 'admin_pro#authorize' - get 'admin/wizards/pro/authorize/callback' => 'admin_pro#authorize_callback' - delete 'admin/wizards/pro/authorize' => 'admin_pro#destroy_authentication' - post 'admin/wizards/pro/subscription' => 'admin_pro#update_subscription' + get 'admin/wizards/subscription' => 'admin_subscription#index' + post 'admin/wizards/subscription' => 'admin_subscription#update_subscription' + get 'admin/wizards/subscription/authorize' => 'admin_subscription#authorize' + get 'admin/wizards/subscription/authorize/callback' => 'admin_subscription#authorize_callback' + delete 'admin/wizards/subscription/authorize' => 'admin_subscription#destroy_authentication' + + get 'admin/wizards/notice' => 'admin_notice#index' + put 'admin/wizards/notice/:notice_id' => 'admin_notice#dismiss' end end diff --git a/controllers/custom_wizard/admin/admin.rb b/controllers/custom_wizard/admin/admin.rb index c99954d6..ff01ddac 100644 --- a/controllers/custom_wizard/admin/admin.rb +++ b/controllers/custom_wizard/admin/admin.rb @@ -3,6 +3,12 @@ class CustomWizard::AdminController < ::Admin::AdminController before_action :ensure_admin def index + render_json_dump( + notices: ActiveModel::ArraySerializer.new( + CustomWizard::Notice.list, + each_serializer: CustomWizard::NoticeSerializer + ) + ) end private diff --git a/controllers/custom_wizard/admin/custom_fields.rb b/controllers/custom_wizard/admin/custom_fields.rb index 40ff64be..d10f82ed 100644 --- a/controllers/custom_wizard/admin/custom_fields.rb +++ b/controllers/custom_wizard/admin/custom_fields.rb @@ -3,7 +3,7 @@ class CustomWizard::AdminCustomFieldsController < CustomWizard::AdminController def index render_json_dump( custom_fields: custom_field_list, - pro_subscribed: CustomWizard::Pro.subscribed? + subscribed: CustomWizard::Subscription.subscribed? ) end diff --git a/controllers/custom_wizard/admin/notice.rb b/controllers/custom_wizard/admin/notice.rb new file mode 100644 index 00000000..bb332810 --- /dev/null +++ b/controllers/custom_wizard/admin/notice.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class CustomWizard::AdminNoticeController < CustomWizard::AdminController + before_action :find_notice, only: [:dismiss] + + def index + render_serialized(CustomWizard::Notice.list, CustomWizard::NoticeSerializer) + end + + def dismiss + if @notice.dismissable? && @notice.dismiss + render json: success_json.merge(dismissed_at: @notice.dismissed_at) + else + render json: failed_json + end + end + + def find_notice + @notice = CustomWizard::Notice.find(params[:notice_id]) + raise Discourse::InvalidParameters.new(:notice_id) unless @notice + end +end \ No newline at end of file diff --git a/controllers/custom_wizard/admin/pro.rb b/controllers/custom_wizard/admin/pro.rb deleted file mode 100644 index 650743e6..00000000 --- a/controllers/custom_wizard/admin/pro.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -class CustomWizard::AdminProController < CustomWizard::AdminController - skip_before_action :check_xhr, :preload_json, :verify_authenticity_token, only: [:authorize, :authorize_callback] - - def index - render_serialized(pro, CustomWizard::ProSerializer, root: false) - end - - def authorize - request_id = SecureRandom.hex(32) - cookies[:user_api_request_id] = request_id - redirect_to pro.authentication_url(current_user.id, request_id).to_s - end - - def authorize_callback - payload = params[:payload] - request_id = cookies[:user_api_request_id] - - pro.authentication_response(request_id, payload) - pro.update_subscription - - redirect_to '/admin/wizards/pro' - end - - def destroy_authentication - if pro.destroy_authentication - render json: success_json - else - render json: failed_json - end - end - - def update_subscription - if pro.update_subscription - subscription = CustomWizard::ProSubscriptionSerializer.new(pro.subscription, root: false) - render json: success_json.merge(subscription: subscription) - else - render json: failed_json - end - end - - protected - - def pro - @pro ||= CustomWizard::Pro.new - end -end diff --git a/controllers/custom_wizard/admin/subscription.rb b/controllers/custom_wizard/admin/subscription.rb new file mode 100644 index 00000000..15ff6396 --- /dev/null +++ b/controllers/custom_wizard/admin/subscription.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +class CustomWizard::AdminSubscriptionController < CustomWizard::AdminController + skip_before_action :check_xhr, :preload_json, :verify_authenticity_token, only: [:authorize, :authorize_callback] + + def index + render_serialized(subscription, CustomWizard::SubscriptionSerializer, root: false) + end + + def authorize + request_id = SecureRandom.hex(32) + cookies[:user_api_request_id] = request_id + redirect_to subscription.authentication_url(current_user.id, request_id).to_s + end + + def authorize_callback + payload = params[:payload] + request_id = cookies[:user_api_request_id] + + subscription.authentication_response(request_id, payload) + subscription.update + + redirect_to '/admin/wizards/subscription' + end + + def destroy_authentication + if subscription.destroy_authentication + render json: success_json + else + render json: failed_json + end + end + + def update_subscription + if subscription.update + serialized_subscription = CustomWizard::Subscription::SubscriptionSerializer.new(subscription.subscription, root: false) + render json: success_json.merge(subscription: serialized_subscription) + else + render json: failed_json + end + end + + protected + + def subscription + @subscription ||= CustomWizard::Subscription.new + end +end diff --git a/controllers/custom_wizard/admin/wizard.rb b/controllers/custom_wizard/admin/wizard.rb index e824398c..fdf338bf 100644 --- a/controllers/custom_wizard/admin/wizard.rb +++ b/controllers/custom_wizard/admin/wizard.rb @@ -11,7 +11,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController field_types: CustomWizard::Field.types, realtime_validations: CustomWizard::RealtimeValidation.types, custom_fields: custom_field_list, - pro_subscribed: CustomWizard::Pro.subscribed? + subscribed: CustomWizard::Subscription.subscribed? ) end diff --git a/controllers/custom_wizard/wizard.rb b/controllers/custom_wizard/wizard.rb index 732c5d5e..40db52e6 100644 --- a/controllers/custom_wizard/wizard.rb +++ b/controllers/custom_wizard/wizard.rb @@ -5,7 +5,7 @@ class CustomWizard::WizardController < ::ApplicationController layout 'wizard' before_action :ensure_plugin_enabled - before_action :update_pro_subscription, only: [:index] + before_action :update_subscription, only: [:index] helper_method :wizard_page_title helper_method :wizard_theme_id helper_method :wizard_theme_lookup @@ -84,7 +84,7 @@ class CustomWizard::WizardController < ::ApplicationController end end - def update_pro_subscription - CustomWizard::Pro.update_subscription + def update_subscription + CustomWizard::Subscription.update end end diff --git a/coverage/.last_run.json b/coverage/.last_run.json index 23e2ecb9..1c721888 100644 --- a/coverage/.last_run.json +++ b/coverage/.last_run.json @@ -1,5 +1,5 @@ { "result": { - "line": 92.14 + "line": 92.3 } } diff --git a/jobs/scheduled/custom_wizard/update_notices.rb b/jobs/scheduled/custom_wizard/update_notices.rb new file mode 100644 index 00000000..5194e2b8 --- /dev/null +++ b/jobs/scheduled/custom_wizard/update_notices.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class Jobs::CustomWizardUpdateNotices < ::Jobs::Scheduled + every 5.minutes + + def execute(args = {}) + CustomWizard::Notice.update + end +end \ No newline at end of file diff --git a/jobs/scheduled/custom_wizard/update_subscription.rb b/jobs/scheduled/custom_wizard/update_subscription.rb new file mode 100644 index 00000000..72e34435 --- /dev/null +++ b/jobs/scheduled/custom_wizard/update_subscription.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class Jobs::CustomWizardUpdateSubscription < ::Jobs::Scheduled + every 1.hour + + def execute(args = {}) + CustomWizard::Subscription.update + end +end diff --git a/jobs/scheduled/update_pro_subscription.rb b/jobs/scheduled/update_pro_subscription.rb deleted file mode 100644 index c790d529..00000000 --- a/jobs/scheduled/update_pro_subscription.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -class CustomWizard::UpdateProSubscription < ::Jobs::Scheduled - every 1.hour - - def execute(args = {}) - CustomWizard::Pro.update_subscription - end -end diff --git a/lib/custom_wizard/action.rb b/lib/custom_wizard/action.rb index 8ee11e54..113a0393 100644 --- a/lib/custom_wizard/action.rb +++ b/lib/custom_wizard/action.rb @@ -749,8 +749,4 @@ class CustomWizard::Action @log.join('; ') ) end - - def pro_actions - %w[send_message watch_categories send_to_api create_group create_category] - end end diff --git a/lib/custom_wizard/custom_field.rb b/lib/custom_wizard/custom_field.rb index bc1a146d..eb93e292 100644 --- a/lib/custom_wizard/custom_field.rb +++ b/lib/custom_wizard/custom_field.rb @@ -17,9 +17,9 @@ class ::CustomWizard::CustomField category: ["basic_category"], post: ["post"] } - PRO_CLASSES ||= ['category', 'group'] + SUBSCRIPTION_CLASSES ||= ['category', 'group'] TYPES ||= ["string", "boolean", "integer", "json"] - PRO_TYPES ||= ["json"] + SUBSCRIPTION_TYPES ||= ["json"] LIST_CACHE_KEY ||= 'custom_field_list' def self.serializers @@ -40,7 +40,7 @@ class ::CustomWizard::CustomField end end - @pro = CustomWizard::Pro.new + @subscription = CustomWizard::Subscription.new end def save @@ -85,8 +85,8 @@ class ::CustomWizard::CustomField next end - if attr == 'klass' && PRO_CLASSES.include?(value) && !@pro.subscribed? - add_error(I18n.t("wizard.custom_field.error.pro_type", type: value)) + if attr == 'klass' && SUBSCRIPTION_CLASSES.include?(value) && !@subscription.subscribed? + add_error(I18n.t("wizard.custom_field.error.subscription_type", type: value)) end if attr == 'serializers' && (unsupported = value - CLASSES[klass.to_sym]).length > 0 @@ -100,8 +100,8 @@ class ::CustomWizard::CustomField add_error(I18n.t("#{i18n_key}.unsupported_type", type: value)) end - if attr == 'type' && PRO_TYPES.include?(value) && !@pro.subscribed? - add_error(I18n.t("wizard.custom_field.error.pro_type", type: value)) + if attr == 'type' && SUBSCRIPTION_TYPES.include?(value) && !@subscription.subscribed? + add_error(I18n.t("wizard.custom_field.error.subscription_type", type: value)) end if attr == 'name' diff --git a/lib/custom_wizard/mapper.rb b/lib/custom_wizard/mapper.rb index b66c1716..05d19a1d 100644 --- a/lib/custom_wizard/mapper.rb +++ b/lib/custom_wizard/mapper.rb @@ -47,7 +47,7 @@ class CustomWizard::Mapper @data = params[:data] || {} @user = params[:user] @opts = params[:opts] || {} - @pro = CustomWizard::Pro.new + @subscription = CustomWizard::Subscription.new end def perform @@ -252,7 +252,7 @@ class CustomWizard::Mapper end end - if opts[:template] && @pro.subscribed? + if opts[:template] && @subscription.subscribed? template = Liquid::Template.parse(string) string = template.render(data) end diff --git a/lib/custom_wizard/notice.rb b/lib/custom_wizard/notice.rb new file mode 100644 index 00000000..096cc579 --- /dev/null +++ b/lib/custom_wizard/notice.rb @@ -0,0 +1,234 @@ +# frozen_string_literal: true + +class CustomWizard::Notice + include ActiveModel::Serialization + + PLUGIN_STATUSES_TO_WARN = %w(incompatible tests_failing) + + attr_reader :id, + :message, + :type, + :created_at + + attr_accessor :retrieved_at, + :dismissed_at, + :expired_at + + def initialize(attrs) + @id = Digest::SHA1.hexdigest(attrs[:message]) + @message = attrs[:message] + @type = attrs[:type].to_i + @created_at = attrs[:created_at] + @retrieved_at = attrs[:retrieved_at] + @dismissed_at = attrs[:dismissed_at] + @expired_at = attrs[:expired_at] + end + + def dismiss + if dismissable? + self.dismissed_at = Time.now + self.save + end + end + + def expire + self.expired_at = Time.now + self.save + end + + def expired? + expired_at.present? + end + + def dismissed? + dismissed_at.present? + end + + def dismissable? + true + end + + def save + attrs = { + expired_at: expired_at, + created_at: created_at, + expired_at: expired_at, + message: message, + type: type + } + + if current = self.class.find(self.id) + attrs[:dismissed_at] = current.dismissed_at || self.dismissed_at + end + + self.class.store(id, attrs) + end + + def self.types + @types ||= Enum.new( + info: 0, + warning: 1 + ) + end + + def self.connection_types + @connection_types ||= Enum.new( + plugin_status: 0, + subscription: 1 + ) + end + + def self.update(skip_subscription: false, skip_plugin: false) + notices = [] + + if !skip_subscription + subscription_messages = request(subscription_messages_url) + if subscription_messages.present? + subscription_notices = convert_subscription_messages_to_notices(subscription_messages[:messages]) + notices.push(*subscription_notices) + end + end + + if !skip_plugin && (Discourse.git_branch === 'tests-passed' || (Rails.env.test? || Rails.env.development?)) + plugin_status = request(plugin_status_url) + + if plugin_status.present? && plugin_status[:status].present? && plugin_status[:status].is_a?(Hash) + plugin_notice = convert_plugin_status_to_notice(plugin_status[:status]) + notices.push(plugin_notice) if plugin_notice + + expire_connection_errors(connection_types[:plugin_status]) + else + create_connection_error(connection_types[:plugin_status]) + end + end + + notices.each do |notice_data| + notice = new(notice_data) + notice.retrieved_at = Time.now + notice.save + end + + if reached_connection_error_limit(connection_types[:plugin_status]) + new( + message: I18n.t("wizard.notice.plugin_status_connection_error_limit"), + type: types[:warning], + created_at: Time.now + ) + end + end + + def self.convert_subscription_messages_to_notices(messages) + messages.map do |message| + { + message: message[:message], + type: types[message[:type].to_sym], + created_at: message[:created_at], + expired_at: message[:expired_at] + } + end + end + + def self.convert_plugin_status_to_notice(plugin_status) + notice = nil + + if PLUGIN_STATUSES_TO_WARN.include?(plugin_status[:status]) + notice = { + message: PrettyText.cook(I18n.t('wizard.notice.compatibility_issue', server: plugin_status_domain)), + type: types[:warning], + created_at: plugin_status[:status_changed_at] + } + else + list(types[:warning]).each(&:expire) + end + + notice + end + + def self.subscription_messages_domain + "localhost:3000" + end + + def self.subscription_messages_url + "http://#{subscription_messages_domain}/subscription-server/messages.json" + end + + def self.plugin_status_domain + "localhost:4200" + end + + def self.plugin_status_url + "http://#{plugin_status_domain}/plugin-manager/status/discourse-custom-wizard" + end + + def self.request(url) + response = Excon.get(url) + + if response.status == 200 + begin + data = JSON.parse(response.body).deep_symbolize_keys + rescue JSON::ParserError + return nil + end + + data + else + nil + end + end + + def self.namespace + "#{CustomWizard::PLUGIN_NAME}_notice" + end + + def self.namespace_connection + "#{CustomWizard::PLUGIN_NAME}_notice_connection" + end + + def self.find(id) + raw = PluginStore.get(namespace, id) + new(raw.symbolize_keys) if raw.present? + end + + def self.store(id, raw_notice) + PluginStore.set(namespace, id, raw_notice) + end + + def self.plugin_status_connection_error_limit + 5 + end + + def self.list_connection_query(type) + query = PluginStoreRow.where(plugin_name: namespace_connection) + query.where("(value::json->>'type')::integer = ?", type) + end + + def self.expire_connection_errors(type) + list_connection_query(type).update_all("value = jsonb_set(value::jsonb, '{ expired_at }', (to_char(current_timestamp, 'HH12:MI:SS'))::jsonb)") + end + + def self.create_connection_error(type) + id = SecureRandom.hex(16) + attrs = { + message: I18n.t("wizard.notice.connection_error", domain: self.send("#{type}_domain")), + type: type, + created_at: Time.now + } + PluginStore.set(namespace_connection, id, attrs) + end + + def self.reached_connection_error_limit(type) + list_connection_query(type).size >= self.send("#{connection_types.key(type)}_connection_error_limit") + end + + def self.list_query(type = nil) + query = PluginStoreRow.where(plugin_name: namespace) + query = query.where("(value::json->>'expired_at') IS NULL OR (value::json->>'expired_at')::date > now()::date - 1") + query = query.where("(value::json->>'type')::integer = ?", type) if type + query.order("value::json->>'created_at' DESC") + end + + def self.list(type = nil) + list_query(type) + .map { |r| self.new(JSON.parse(r.value).symbolize_keys) } + end +end diff --git a/lib/custom_wizard/pro.rb b/lib/custom_wizard/subscription.rb similarity index 81% rename from lib/custom_wizard/pro.rb rename to lib/custom_wizard/subscription.rb index 61097069..11e6d4d3 100644 --- a/lib/custom_wizard/pro.rb +++ b/lib/custom_wizard/subscription.rb @@ -1,14 +1,14 @@ # frozen_string_literal: true -class CustomWizard::Pro +class CustomWizard::Subscription include ActiveModel::Serialization attr_accessor :authentication, :subscription def initialize - @authentication = CustomWizard::ProAuthentication.new(get_authentication) - @subscription = CustomWizard::ProSubscription.new(get_subscription) + @authentication = CustomWizard::Subscription::Authentication.new(get_authentication) + @subscription = CustomWizard::Subscription::Subscription.new(get_subscription) end def authorized? @@ -35,7 +35,7 @@ class CustomWizard::Pro "discourse-subscription-server:user_subscription" end - def update_subscription + def update if @authentication.active? response = Excon.get( "https://#{server}/subscription-server/user-subscriptions/#{subscription_type}/#{client_name}", @@ -67,7 +67,7 @@ class CustomWizard::Pro def destroy_subscription if remove_subscription - @subscription = CustomWizard::ProSubscription.new(get_subscription) + @subscription = CustomWizard::Subscription::Subscription.new(get_subscription) !@subscription.active? else false @@ -80,7 +80,7 @@ class CustomWizard::Pro public_key: keys.public_key, nonce: keys.nonce, client_id: @authentication.client_id, - auth_redirect: "#{Discourse.base_url}/admin/wizards/pro/authorize/callback", + auth_redirect: "#{Discourse.base_url}/admin/wizards/subscription/authorize/callback", application_name: SiteSetting.title, scopes: scope } @@ -108,7 +108,7 @@ class CustomWizard::Pro def destroy_authentication if remove_authentication - @authentication = CustomWizard::ProAuthentication.new(get_authentication) + @authentication = CustomWizard::Subscription::Authentication.new(get_authentication) !@authentication.active? else false @@ -123,12 +123,12 @@ class CustomWizard::Pro self.new.authorized? end - def self.update_subscription - self.new.update_subscription + def self.update + self.new.update end def self.namespace - "custom_wizard_pro" + "custom_wizard_subscription" end private @@ -157,8 +157,8 @@ class CustomWizard::Pro end def set_subscription(type) - PluginStore.set(CustomWizard::Pro.namespace, subscription_db_key, type: type, updated_at: Time.now) - CustomWizard::ProSubscription.new(get_subscription) + PluginStore.set(CustomWizard::Subscription.namespace, subscription_db_key, type: type, updated_at: Time.now) + CustomWizard::Subscription::Subscription.new(get_subscription) end def get_authentication @@ -176,7 +176,7 @@ class CustomWizard::Pro auth_by: user_id, auth_at: Time.now ) - CustomWizard::ProAuthentication.new(get_authentication) + CustomWizard::Subscription::Authentication.new(get_authentication) end def remove_authentication diff --git a/lib/custom_wizard/pro/authentication.rb b/lib/custom_wizard/subscription/authentication.rb similarity index 77% rename from lib/custom_wizard/pro/authentication.rb rename to lib/custom_wizard/subscription/authentication.rb index 23603898..7ad02d2c 100644 --- a/lib/custom_wizard/pro/authentication.rb +++ b/lib/custom_wizard/subscription/authentication.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -class CustomWizard::ProAuthentication +class CustomWizard::Subscription::Authentication include ActiveModel::Serialization attr_reader :client_id, @@ -53,7 +53,7 @@ class CustomWizard::ProAuthentication end def get_keys(request_id) - raw = PluginStore.get(CustomWizard::Pro.namespace, "#{keys_db_key}_#{request_id}") + raw = PluginStore.get(CustomWizard::Subscription.namespace, "#{keys_db_key}_#{request_id}") OpenStruct.new( user_id: raw && raw['user_id'], pem: raw && raw['pem'], @@ -72,7 +72,7 @@ class CustomWizard::ProAuthentication end def set_keys(request_id, user_id, rsa, nonce) - PluginStore.set(CustomWizard::Pro.namespace, "#{keys_db_key}_#{request_id}", + PluginStore.set(CustomWizard::Subscription.namespace, "#{keys_db_key}_#{request_id}", user_id: user_id, pem: rsa.export, nonce: nonce @@ -80,16 +80,16 @@ class CustomWizard::ProAuthentication end def delete_keys(request_id) - PluginStore.remove(CustomWizard::Pro.namespace, "#{keys_db_key}_#{request_id}") + PluginStore.remove(CustomWizard::Subscription.namespace, "#{keys_db_key}_#{request_id}") end def get_client_id - PluginStore.get(CustomWizard::Pro.namespace, client_id_db_key) + PluginStore.get(CustomWizard::Subscription.namespace, client_id_db_key) end def set_client_id client_id = SecureRandom.hex(32) - PluginStore.set(CustomWizard::Pro.namespace, client_id_db_key, client_id) + PluginStore.set(CustomWizard::Subscription.namespace, client_id_db_key, client_id) client_id end end diff --git a/lib/custom_wizard/pro/subscription.rb b/lib/custom_wizard/subscription/subscription.rb similarity index 89% rename from lib/custom_wizard/pro/subscription.rb rename to lib/custom_wizard/subscription/subscription.rb index 7f5cf911..129f993a 100644 --- a/lib/custom_wizard/pro/subscription.rb +++ b/lib/custom_wizard/subscription/subscription.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -class CustomWizard::ProSubscription +class CustomWizard::Subscription::Subscription include ActiveModel::Serialization attr_reader :type, diff --git a/lib/custom_wizard/validators/template.rb b/lib/custom_wizard/validators/template.rb index 4311bbbc..4928c4e5 100644 --- a/lib/custom_wizard/validators/template.rb +++ b/lib/custom_wizard/validators/template.rb @@ -6,7 +6,7 @@ class CustomWizard::TemplateValidator def initialize(data, opts = {}) @data = data @opts = opts - @pro = CustomWizard::Pro.new + @subscription = CustomWizard::Subscription.new end def perform @@ -15,15 +15,15 @@ class CustomWizard::TemplateValidator check_id(data, :wizard) check_required(data, :wizard) validate_after_time - validate_pro(data, :wizard) + validate_subscription(data, :wizard) data[:steps].each do |step| check_required(step, :step) - validate_pro(step, :step) + validate_subscription(step, :step) if step[:fields].present? step[:fields].each do |field| - validate_pro(field, :field) + validate_subscription(field, :field) check_required(field, :field) end end @@ -31,7 +31,7 @@ class CustomWizard::TemplateValidator if data[:actions].present? data[:actions].each do |action| - validate_pro(action, :action) + validate_subscription(action, :action) check_required(action, :action) end end @@ -52,7 +52,7 @@ class CustomWizard::TemplateValidator } end - def self.pro + def self.subscription { wizard: { save_submissions: 'false', @@ -90,18 +90,18 @@ class CustomWizard::TemplateValidator end end - def validate_pro(object, type) - self.class.pro[type].each do |property, pro_type| + def validate_subscription(object, type) + self.class.subscription[type].each do |property, subscription_type| val = object[property.to_s] - is_pro = (val != nil) && ( - pro_type === 'present' && val.present? || - (['true', 'false'].include?(pro_type) && cast_bool(val) == cast_bool(pro_type)) || - (pro_type === 'conditional' && val.is_a?(Hash)) || - (pro_type.is_a?(Array) && pro_type.include?(val)) + is_subscription = (val != nil) && ( + subscription_type === 'present' && val.present? || + (['true', 'false'].include?(subscription_type) && cast_bool(val) == cast_bool(subscription_type)) || + (subscription_type === 'conditional' && val.is_a?(Hash)) || + (subscription_type.is_a?(Array) && subscription_type.include?(val)) ) - if is_pro && !@pro.subscribed? - errors.add :base, I18n.t("wizard.validation.pro", type: type.to_s, property: property) + if is_subscription && !@subscription.subscribed? + errors.add :base, I18n.t("wizard.validation.subscription", type: type.to_s, property: property) end end end diff --git a/plugin.rb b/plugin.rb index 808975d6..c3063d29 100644 --- a/plugin.rb +++ b/plugin.rb @@ -7,9 +7,7 @@ # contact emails: angus@thepavilion.io gem 'liquid', '5.0.1', require: true -register_asset 'stylesheets/common/wizard-admin.scss' -register_asset 'stylesheets/common/wizard-mapper.scss' - +register_asset 'stylesheets/admin/admin.scss', :desktop enabled_site_setting :custom_wizard_enabled config = Rails.application.config @@ -42,6 +40,7 @@ if respond_to?(:register_svg_icon) register_svg_icon "comment-alt" register_svg_icon "far-life-ring" register_svg_icon "arrow-right" + register_svg_icon "shield-virus" end class ::Sprockets::DirectiveProcessor @@ -71,13 +70,15 @@ after_initialize do ../controllers/custom_wizard/admin/logs.rb ../controllers/custom_wizard/admin/manager.rb ../controllers/custom_wizard/admin/custom_fields.rb - ../controllers/custom_wizard/admin/pro.rb + ../controllers/custom_wizard/admin/subscription.rb + ../controllers/custom_wizard/admin/notice.rb ../controllers/custom_wizard/wizard.rb ../controllers/custom_wizard/steps.rb ../controllers/custom_wizard/realtime_validations.rb ../jobs/regular/refresh_api_access_token.rb ../jobs/regular/set_after_time_wizard.rb - ../jobs/scheduled/update_pro_subscription.rb + ../jobs/scheduled/custom_wizard/update_subscription.rb + ../jobs/scheduled/custom_wizard/update_notices.rb ../lib/custom_wizard/validators/template.rb ../lib/custom_wizard/validators/update.rb ../lib/custom_wizard/action_result.rb @@ -96,9 +97,10 @@ after_initialize do ../lib/custom_wizard/submission.rb ../lib/custom_wizard/template.rb ../lib/custom_wizard/wizard.rb - ../lib/custom_wizard/pro.rb - ../lib/custom_wizard/pro/subscription.rb - ../lib/custom_wizard/pro/authentication.rb + ../lib/custom_wizard/notice.rb + ../lib/custom_wizard/subscription.rb + ../lib/custom_wizard/subscription/subscription.rb + ../lib/custom_wizard/subscription/authentication.rb ../lib/custom_wizard/api/api.rb ../lib/custom_wizard/api/authorization.rb ../lib/custom_wizard/api/endpoint.rb @@ -119,9 +121,10 @@ after_initialize do ../serializers/custom_wizard/log_serializer.rb ../serializers/custom_wizard/submission_serializer.rb ../serializers/custom_wizard/realtime_validation/similar_topics_serializer.rb - ../serializers/custom_wizard/pro/authentication_serializer.rb - ../serializers/custom_wizard/pro/subscription_serializer.rb - ../serializers/custom_wizard/pro_serializer.rb + ../serializers/custom_wizard/subscription/authentication_serializer.rb + ../serializers/custom_wizard/subscription/subscription_serializer.rb + ../serializers/custom_wizard/subscription_serializer.rb + ../serializers/custom_wizard/notice_serializer.rb ../extensions/extra_locales_controller.rb ../extensions/invites_controller.rb ../extensions/users_controller.rb @@ -238,5 +241,11 @@ after_initialize do "#{serializer_klass}_serializer".classify.constantize.prepend CustomWizardCustomFieldSerializer end + AdminDashboardData.add_problem_check do + warning_notices = CustomWizard::Notice.list(CustomWizard::Notice.types[:warning]) + warning_notices.any? ? ActionView::Base.full_sanitizer.sanitize(warning_notices.first.message, tags: %w(a)) : nil + end + + Jobs.enqueue(:custom_wizard_update_notices) DiscourseEvent.trigger(:custom_wizard_ready) end diff --git a/serializers/custom_wizard/notice_serializer.rb b/serializers/custom_wizard/notice_serializer.rb new file mode 100644 index 00000000..310827f7 --- /dev/null +++ b/serializers/custom_wizard/notice_serializer.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class CustomWizard::NoticeSerializer < ApplicationSerializer + attributes :id, + :message, + :type, + :created_at, + :expired_at, + :dismissed_at, + :retrieved_at, + :dismissable + + def dismissable + object.dismissable? + end + + def type + CustomWizard::Notice.types.key(object.type) + end +end diff --git a/serializers/custom_wizard/pro_serializer.rb b/serializers/custom_wizard/pro_serializer.rb deleted file mode 100644 index 2f141c6d..00000000 --- a/serializers/custom_wizard/pro_serializer.rb +++ /dev/null @@ -1,6 +0,0 @@ -# frozen_string_literal: true -class CustomWizard::ProSerializer < ApplicationSerializer - attributes :server - has_one :authentication, serializer: CustomWizard::ProAuthenticationSerializer, embed: :objects - has_one :subscription, serializer: CustomWizard::ProSubscriptionSerializer, embed: :objects -end diff --git a/serializers/custom_wizard/pro/authentication_serializer.rb b/serializers/custom_wizard/subscription/authentication_serializer.rb similarity index 66% rename from serializers/custom_wizard/pro/authentication_serializer.rb rename to serializers/custom_wizard/subscription/authentication_serializer.rb index 0a2915e4..3d54d0f2 100644 --- a/serializers/custom_wizard/pro/authentication_serializer.rb +++ b/serializers/custom_wizard/subscription/authentication_serializer.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -class CustomWizard::ProAuthenticationSerializer < ApplicationSerializer +class CustomWizard::Subscription::AuthenticationSerializer < ApplicationSerializer attributes :active, :client_id, :auth_by, diff --git a/serializers/custom_wizard/pro/subscription_serializer.rb b/serializers/custom_wizard/subscription/subscription_serializer.rb similarity index 63% rename from serializers/custom_wizard/pro/subscription_serializer.rb rename to serializers/custom_wizard/subscription/subscription_serializer.rb index d3e04e4e..95a2b323 100644 --- a/serializers/custom_wizard/pro/subscription_serializer.rb +++ b/serializers/custom_wizard/subscription/subscription_serializer.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -class CustomWizard::ProSubscriptionSerializer < ApplicationSerializer +class CustomWizard::Subscription::SubscriptionSerializer < ApplicationSerializer attributes :type, :active, :updated_at diff --git a/serializers/custom_wizard/subscription_serializer.rb b/serializers/custom_wizard/subscription_serializer.rb new file mode 100644 index 00000000..067cfbcd --- /dev/null +++ b/serializers/custom_wizard/subscription_serializer.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true +class CustomWizard::SubscriptionSerializer < ApplicationSerializer + attributes :server + has_one :authentication, serializer: CustomWizard::Subscription::AuthenticationSerializer, embed: :objects + has_one :subscription, serializer: CustomWizard::Subscription::SubscriptionSerializer, embed: :objects +end diff --git a/serializers/custom_wizard/wizard_field_serializer.rb b/serializers/custom_wizard/wizard_field_serializer.rb index fc2575ef..bba2b41a 100644 --- a/serializers/custom_wizard/wizard_field_serializer.rb +++ b/serializers/custom_wizard/wizard_field_serializer.rb @@ -123,6 +123,6 @@ class CustomWizard::FieldSerializer < ::ApplicationSerializer end def subscribed? - @subscribed ||= CustomWizard::Pro.subscribed? + @subscribed ||= CustomWizard::Subscription.subscribed? end end diff --git a/serializers/custom_wizard/wizard_serializer.rb b/serializers/custom_wizard/wizard_serializer.rb index 4a29d3ea..fe2ac355 100644 --- a/serializers/custom_wizard/wizard_serializer.rb +++ b/serializers/custom_wizard/wizard_serializer.rb @@ -10,7 +10,7 @@ class CustomWizard::WizardSerializer < CustomWizard::BasicWizardSerializer :permitted, :uncategorized_category_id, :categories, - :pro_subscribed + :subscribed has_many :steps, serializer: ::CustomWizard::StepSerializer, embed: :objects has_one :user, serializer: ::BasicUserSerializer, embed: :objects @@ -62,7 +62,7 @@ class CustomWizard::WizardSerializer < CustomWizard::BasicWizardSerializer object.categories.map { |c| c.to_h } end - def pro_subscribed - CustomWizard::Pro.subscribed? + def subscribed + CustomWizard::Subscription.subscribed? end end diff --git a/serializers/custom_wizard/wizard_step_serializer.rb b/serializers/custom_wizard/wizard_step_serializer.rb index 463fa3d6..a2a314a4 100644 --- a/serializers/custom_wizard/wizard_step_serializer.rb +++ b/serializers/custom_wizard/wizard_step_serializer.rb @@ -80,8 +80,4 @@ class CustomWizard::StepSerializer < ::ApplicationSerializer def i18n_key @i18n_key ||= "#{object.wizard.id}.#{object.id}".underscore end - - def subscribed? - @subscribed ||= CustomWizard::Pro.subscribed? - end end diff --git a/spec/components/custom_wizard/action_spec.rb b/spec/components/custom_wizard/action_spec.rb index c92a0d61..e34dd861 100644 --- a/spec/components/custom_wizard/action_spec.rb +++ b/spec/components/custom_wizard/action_spec.rb @@ -174,7 +174,7 @@ describe CustomWizard::Action do expect(updater.result[:redirect_on_next]).to eq("https://google.com") end - context "pro actions" do + context "subscription actions" do before do enable_subscription end diff --git a/spec/components/custom_wizard/custom_field_spec.rb b/spec/components/custom_wizard/custom_field_spec.rb index 3bcfab46..a30ec02b 100644 --- a/spec/components/custom_wizard/custom_field_spec.rb +++ b/spec/components/custom_wizard/custom_field_spec.rb @@ -4,7 +4,7 @@ require_relative '../../plugin_helper' describe CustomWizard::CustomField do let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") } - let(:custom_field_pro_json) { get_wizard_fixture("custom_field/pro_custom_fields") } + let(:custom_field_subscription_json) { get_wizard_fixture("custom_field/subscription_custom_fields") } before do CustomWizard::CustomField.invalidate_cache @@ -193,44 +193,44 @@ describe CustomWizard::CustomField do ).to eq(false) end - it "does not save pro field types without a pro subscription" do - pro_field_json = custom_field_pro_json['custom_fields'].first - custom_field = CustomWizard::CustomField.new(nil, pro_field_json) + it "does not save subscription field types without a subscription" do + subscription_field_json = custom_field_subscription_json['custom_fields'].first + custom_field = CustomWizard::CustomField.new(nil, subscription_field_json) expect(custom_field.save).to eq(false) expect(custom_field.valid?).to eq(false) expect(custom_field.errors.full_messages.first).to eq( - I18n.t("wizard.custom_field.error.pro_type", type: "json") + I18n.t("wizard.custom_field.error.subscription_type", type: "json") ) end - it "does not save pro field classes without a pro subscription" do - pro_field_json = custom_field_pro_json['custom_fields'].second - custom_field = CustomWizard::CustomField.new(nil, pro_field_json) + it "does not save subscription field classes without a subscription" do + subscription_field_json = custom_field_subscription_json['custom_fields'].second + custom_field = CustomWizard::CustomField.new(nil, subscription_field_json) expect(custom_field.save).to eq(false) expect(custom_field.valid?).to eq(false) expect(custom_field.errors.full_messages.first).to eq( - I18n.t("wizard.custom_field.error.pro_type", type: "category") + I18n.t("wizard.custom_field.error.subscription_type", type: "category") ) end - context "with a pro subscription" do + context "with a subscription" do before do enable_subscription end - it "saves pro field types" do - pro_field_json = custom_field_pro_json['custom_fields'].first - custom_field = CustomWizard::CustomField.new(nil, pro_field_json) + it "saves subscription field types" do + subscription_field_json = custom_field_subscription_json['custom_fields'].first + custom_field = CustomWizard::CustomField.new(nil, subscription_field_json) expect(custom_field.save).to eq(true) expect(custom_field.valid?).to eq(true) end - it "saves pro field classes" do - pro_field_json = custom_field_pro_json['custom_fields'].second - custom_field = CustomWizard::CustomField.new(nil, pro_field_json) + it "saves subscription field classes" do + subscription_field_json = custom_field_subscription_json['custom_fields'].second + custom_field = CustomWizard::CustomField.new(nil, subscription_field_json) expect(custom_field.save).to eq(true) expect(custom_field.valid?).to eq(true) diff --git a/spec/components/custom_wizard/mapper_spec.rb b/spec/components/custom_wizard/mapper_spec.rb index 7ef2a5a8..1ac945d0 100644 --- a/spec/components/custom_wizard/mapper_spec.rb +++ b/spec/components/custom_wizard/mapper_spec.rb @@ -344,7 +344,7 @@ describe CustomWizard::Mapper do expect(result).to eq(template_params["step_1_field_1"]) end - it "requires a pro subscription" do + it "requires a subscription" do template = '{{ "w{step_1_field_1}" | size }}' mapper = create_template_mapper(template_params, user1) result = mapper.interpolate( @@ -357,7 +357,7 @@ describe CustomWizard::Mapper do expect(result).to eq("{{ \"#{template_params["step_1_field_1"]}\" | size }}") end - context "with a pro subscription" do + context "with a subscription" do before do enable_subscription end diff --git a/spec/components/custom_wizard/notice_spec.rb b/spec/components/custom_wizard/notice_spec.rb new file mode 100644 index 00000000..373d2e31 --- /dev/null +++ b/spec/components/custom_wizard/notice_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require_relative '../../plugin_helper' + +describe CustomWizard::Notice do + fab!(:user) { Fabricate(:user) } + let(:subscription_message) { + { + message: "Message about subscription", + type: "info", + created_at: Time.now - 3.day, + expired_at: nil + } + } + let(:plugin_status) { + { + name: 'discourse-custom-wizard', + status: 'incompatible', + status_changed_at: Time.now - 3.day + } + } + + context "subscription message" do + before do + freeze_time + stub_request(:get, described_class.subscription_messages_url).to_return(status: 200, body: { messages: [subscription_message] }.to_json) + described_class.update(skip_plugin: true) + end + + it "converts subscription messages into notices" do + notice = described_class.list.first + expect(notice.type).to eq(described_class.types[:info]) + expect(notice.message).to eq(subscription_message[:message]) + expect(notice.created_at.to_datetime).to be_within(1.second).of (subscription_message[:created_at].to_datetime) + end + + it "expires notice if subscription message is expired" do + subscription_message[:expired_at] = Time.now + stub_request(:get, described_class.subscription_messages_url).to_return(status: 200, body: { messages: [subscription_message] }.to_json) + described_class.update(skip_plugin: true) + + notice = described_class.list.first + expect(notice.expired?).to eq(true) + end + end + + context "plugin status" do + before do + freeze_time + stub_request(:get, described_class.plugin_status_url).to_return(status: 200, body: { status: plugin_status }.to_json) + described_class.update(skip_subscription: true) + end + + it "converts plugin statuses to warn into notices" do + notice = described_class.list.first + expect(notice.type).to eq(described_class.types[:warning]) + expect(notice.message).to eq(PrettyText.cook(I18n.t("wizard.notice.compatibility_issue", server: described_class.plugin_status_domain))) + expect(notice.created_at.to_datetime).to be_within(1.second).of (plugin_status[:status_changed_at].to_datetime) + end + + it "expires unexpired warning notices if status is recommended or compatible" do + plugin_status[:status] = 'compatible' + plugin_status[:status_changed_at] = Time.now + stub_request(:get, described_class.plugin_status_url).to_return(status: 200, body: { status: plugin_status }.to_json) + described_class.update(skip_subscription: true) + + notice = described_class.list(described_class.types[:warning]).first + expect(notice.expired?).to eq(true) + end + end + + it "lists notices not expired more than a day ago" do + subscription_message[:expired_at] = Time.now - 8.hours + stub_request(:get, described_class.subscription_messages_url).to_return(status: 200, body: { messages: [subscription_message] }.to_json) + stub_request(:get, described_class.plugin_status_url).to_return(status: 200, body: { status: plugin_status }.to_json) + + described_class.update + expect(described_class.list.length).to eq(2) + end +end \ No newline at end of file diff --git a/spec/components/custom_wizard/pro_spec.rb b/spec/components/custom_wizard/subscription_spec.rb similarity index 54% rename from spec/components/custom_wizard/pro_spec.rb rename to spec/components/custom_wizard/subscription_spec.rb index 6499b668..47fb2d3f 100644 --- a/spec/components/custom_wizard/pro_spec.rb +++ b/spec/components/custom_wizard/subscription_spec.rb @@ -2,69 +2,69 @@ require_relative '../../plugin_helper' -describe CustomWizard::Pro do +describe CustomWizard::Subscription do fab!(:user) { Fabricate(:user) } - it "initializes pro authentication and subscription" do - pro = described_class.new - expect(pro.authentication.class).to eq(CustomWizard::ProAuthentication) - expect(pro.subscription.class).to eq(CustomWizard::ProSubscription) + it "initializes subscription authentication and subscription" do + subscription = described_class.new + expect(subscription.authentication.class).to eq(CustomWizard::Subscription::Authentication) + expect(subscription.subscription.class).to eq(CustomWizard::Subscription::Subscription) end it "returns authorized and subscribed states" do - pro = described_class.new - expect(pro.authorized?).to eq(false) - expect(pro.subscribed?).to eq(false) + subscription = described_class.new + expect(subscription.authorized?).to eq(false) + expect(subscription.subscribed?).to eq(false) end context "subscription" do before do - @pro = described_class.new + @subscription = described_class.new end it "updates valid subscriptions" do stub_subscription_request(200, valid_subscription) - expect(@pro.update_subscription).to eq(true) - expect(@pro.subscribed?).to eq(true) + expect(@subscription.update).to eq(true) + expect(@subscription.subscribed?).to eq(true) end it "handles invalid subscriptions" do stub_subscription_request(200, invalid_subscription) - expect(@pro.update_subscription).to eq(false) - expect(@pro.subscribed?).to eq(false) + expect(@subscription.update).to eq(false) + expect(@subscription.subscribed?).to eq(false) end it "handles subscription http errors" do stub_subscription_request(404, {}) - expect(@pro.update_subscription).to eq(false) - expect(@pro.subscribed?).to eq(false) + expect(@subscription.update).to eq(false) + expect(@subscription.subscribed?).to eq(false) end it "destroys subscriptions" do stub_subscription_request(200, valid_subscription) - expect(@pro.update_subscription).to eq(true) - expect(@pro.destroy_subscription).to eq(true) - expect(@pro.subscribed?).to eq(false) + expect(@subscription.update).to eq(true) + expect(@subscription.destroy_subscription).to eq(true) + expect(@subscription.subscribed?).to eq(false) end it "has class aliases" do - authenticate_pro + authenticate_subscription stub_subscription_request(200, valid_subscription) - expect(described_class.update_subscription).to eq(true) + expect(described_class.update).to eq(true) expect(described_class.subscribed?).to eq(true) end end context "authentication" do before do - @pro = described_class.new + @subscription = described_class.new user.update!(admin: true) end it "generates a valid authentication request url" do request_id = SecureRandom.hex(32) - uri = URI(@pro.authentication_url(user.id, request_id)) - expect(uri.host).to eq(@pro.server) + uri = URI(@subscription.authentication_url(user.id, request_id)) + expect(uri.host).to eq(@subscription.server) parsed_query = Rack::Utils.parse_query uri.query expect(parsed_query['public_key'].present?).to eq(true) @@ -72,12 +72,12 @@ describe CustomWizard::Pro do expect(parsed_query['client_id'].present?).to eq(true) expect(parsed_query['auth_redirect'].present?).to eq(true) expect(parsed_query['application_name']).to eq(SiteSetting.title) - expect(parsed_query['scopes']).to eq(@pro.scope) + expect(parsed_query['scopes']).to eq(@subscription.scope) end def generate_payload(request_id, user_id) - uri = URI(@pro.authentication_url(user_id, request_id)) - keys = @pro.authentication.get_keys(request_id) + uri = URI(@subscription.authentication_url(user_id, request_id)) + keys = @subscription.authentication.get_keys(request_id) raw_payload = { key: "12345", nonce: keys.nonce, @@ -92,8 +92,8 @@ describe CustomWizard::Pro do request_id = SecureRandom.hex(32) payload = generate_payload(request_id, user.id) - expect(@pro.authentication_response(request_id, payload)).to eq(true) - expect(@pro.authorized?).to eq(true) + expect(@subscription.authentication_response(request_id, payload)).to eq(true) + expect(@subscription.authorized?).to eq(true) end it "discards authentication response if user who made request as not an admin" do @@ -102,24 +102,24 @@ describe CustomWizard::Pro do request_id = SecureRandom.hex(32) payload = generate_payload(request_id, user.id) - expect(@pro.authentication_response(request_id, payload)).to eq(false) - expect(@pro.authorized?).to eq(false) + expect(@subscription.authentication_response(request_id, payload)).to eq(false) + expect(@subscription.authorized?).to eq(false) end it "discards authentication response if request_id is invalid" do payload = generate_payload(SecureRandom.hex(32), user.id) - expect(@pro.authentication_response(SecureRandom.hex(32), payload)).to eq(false) - expect(@pro.authorized?).to eq(false) + expect(@subscription.authentication_response(SecureRandom.hex(32), payload)).to eq(false) + expect(@subscription.authorized?).to eq(false) end it "destroys authentication" do request_id = SecureRandom.hex(32) payload = generate_payload(request_id, user.id) - @pro.authentication_response(request_id, payload) + @subscription.authentication_response(request_id, payload) - expect(@pro.destroy_authentication).to eq(true) - expect(@pro.authorized?).to eq(false) + expect(@subscription.destroy_authentication).to eq(true) + expect(@subscription.authorized?).to eq(false) end end end diff --git a/spec/extensions/custom_field_extensions_spec.rb b/spec/extensions/custom_field_extensions_spec.rb index 7ada17a4..7bba27a0 100644 --- a/spec/extensions/custom_field_extensions_spec.rb +++ b/spec/extensions/custom_field_extensions_spec.rb @@ -10,7 +10,7 @@ describe "custom field extensions" do fab!(:user) { Fabricate(:user) } let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") } - let(:pro_custom_field_json) { get_wizard_fixture("custom_field/pro_custom_fields") } + let(:subscription_custom_field_json) { get_wizard_fixture("custom_field/subscription_custom_fields") } before do custom_field_json['custom_fields'].each do |field_json| @@ -72,11 +72,11 @@ describe "custom field extensions" do end end - context "pro custom fields" do + context "subscription custom fields" do before do enable_subscription - pro_custom_field_json['custom_fields'].each do |field_json| + subscription_custom_field_json['custom_fields'].each do |field_json| custom_field = CustomWizard::CustomField.new(nil, field_json) custom_field.save end diff --git a/spec/fixtures/custom_field/pro_custom_fields.json b/spec/fixtures/custom_field/subscription_custom_fields.json similarity index 100% rename from spec/fixtures/custom_field/pro_custom_fields.json rename to spec/fixtures/custom_field/subscription_custom_fields.json diff --git a/spec/jobs/update_notices_spec.rb b/spec/jobs/update_notices_spec.rb new file mode 100644 index 00000000..d0e5a468 --- /dev/null +++ b/spec/jobs/update_notices_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require_relative '../plugin_helper' + +describe Jobs::CustomWizardUpdateNotices do + let(:subscription_message) { + { + message: "Message about subscription", + type: "info", + created_at: Time.now - 3.day, + expired_at: nil + } + } + let(:plugin_status) { + { + name: 'discourse-custom-wizard', + status: 'incompatible', + status_changed_at: Time.now - 3.day + } + } + + it "updates the notices" do + stub_request(:get, CustomWizard::Notice.subscription_messages_url).to_return(status: 200, body: { messages: [subscription_message] }.to_json) + stub_request(:get, CustomWizard::Notice.plugin_status_url).to_return(status: 200, body: { status: plugin_status }.to_json) + + described_class.new.execute + expect(CustomWizard::Notice.list.length).to eq(2) + end +end diff --git a/spec/jobs/update_pro_subscription_spec.rb b/spec/jobs/update_subscription_spec.rb similarity index 52% rename from spec/jobs/update_pro_subscription_spec.rb rename to spec/jobs/update_subscription_spec.rb index 0aae9668..c5adaf38 100644 --- a/spec/jobs/update_pro_subscription_spec.rb +++ b/spec/jobs/update_subscription_spec.rb @@ -2,10 +2,10 @@ require_relative '../plugin_helper' -describe CustomWizard::UpdateProSubscription do - it "updates the pro subscription" do +describe Jobs::CustomWizardUpdateSubscription do + it "updates the subscription" do stub_subscription_request(200, valid_subscription) described_class.new.execute - expect(CustomWizard::Pro.subscribed?).to eq(true) + expect(CustomWizard::Subscription.subscribed?).to eq(true) end end diff --git a/spec/plugin_helper.rb b/spec/plugin_helper.rb index 348e7791..d47c47c1 100644 --- a/spec/plugin_helper.rb +++ b/spec/plugin_helper.rb @@ -24,16 +24,16 @@ def get_wizard_fixture(path) ).with_indifferent_access end -def authenticate_pro - CustomWizard::ProAuthentication.any_instance.stubs(:active?).returns(true) +def authenticate_subscription + CustomWizard::Subscription::Authentication.any_instance.stubs(:active?).returns(true) end def enable_subscription - CustomWizard::Pro.any_instance.stubs(:subscribed?).returns(true) + CustomWizard::Subscription.any_instance.stubs(:subscribed?).returns(true) end -def disable_pro - CustomWizard::Pro.any_instance.stubs(:subscribed?).returns(false) +def disable_subscription + CustomWizard::Subscription.any_instance.stubs(:subscribed?).returns(false) end def valid_subscription @@ -52,7 +52,7 @@ def invalid_subscription end def stub_subscription_request(status, subscription) - authenticate_pro - pro = CustomWizard::Pro.new - stub_request(:get, "https://#{pro.server}/subscription-server/user-subscriptions/#{pro.subscription_type}/#{pro.client_name}").to_return(status: status, body: { subscriptions: [subscription] }.to_json) + authenticate_subscription + sub = CustomWizard::Subscription.new + stub_request(:get, "https://#{sub.server}/subscription-server/user-subscriptions/#{sub.subscription_type}/#{sub.client_name}").to_return(status: status, body: { subscriptions: [subscription] }.to_json) end diff --git a/spec/requests/custom_wizard/admin/notice_controller_spec.rb b/spec/requests/custom_wizard/admin/notice_controller_spec.rb new file mode 100644 index 00000000..bd174e90 --- /dev/null +++ b/spec/requests/custom_wizard/admin/notice_controller_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +require_relative '../../../plugin_helper' + +describe CustomWizard::AdminNoticeController do + fab!(:admin_user) { Fabricate(:user, admin: true) } + + before do + sign_in(admin_user) + @notice = CustomWizard::Notice.new( + message: "Message about subscription", + type: "info", + created_at: Time.now - 3.day, + expired_at: nil + ) + @notice.save + end + + it "lists notices" do + get "/admin/wizards/notice.json" + expect(response.status).to eq(200) + expect(response.parsed_body.length).to eq(1) + end + + it "dismisses notices" do + put "/admin/wizards/notice/#{@notice.id}.json" + expect(response.status).to eq(200) + + updated = CustomWizard::Notice.find(@notice.id) + expect(updated.dismissed?).to eq(true) + end +end diff --git a/spec/requests/custom_wizard/admin/pro_controller_spec.rb b/spec/requests/custom_wizard/admin/subscription_controller_spec.rb similarity index 53% rename from spec/requests/custom_wizard/admin/pro_controller_spec.rb rename to spec/requests/custom_wizard/admin/subscription_controller_spec.rb index 563572bd..2f8aad20 100644 --- a/spec/requests/custom_wizard/admin/pro_controller_spec.rb +++ b/spec/requests/custom_wizard/admin/subscription_controller_spec.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true require_relative '../../../plugin_helper' -describe CustomWizard::AdminProController do +describe CustomWizard::AdminSubscriptionController do fab!(:admin_user) { Fabricate(:user, admin: true) } def generate_payload(request_id, user_id) - uri = URI(@pro.authentication_url(user_id, request_id)) - keys = @pro.authentication.get_keys(request_id) + uri = URI(@subscription.authentication_url(user_id, request_id)) + keys = @subscription.authentication.get_keys(request_id) raw_payload = { key: "12345", nonce: keys.nonce, @@ -18,19 +18,19 @@ describe CustomWizard::AdminProController do end before do - @pro = CustomWizard::Pro.new + @subscription = CustomWizard::Subscription.new sign_in(admin_user) end it "#index" do - get "/admin/wizards/pro.json" - expect(response.parsed_body['server']).to eq(@pro.server) - expect(response.parsed_body['authentication'].deep_symbolize_keys).to eq(CustomWizard::ProAuthenticationSerializer.new(@pro.authentication, root: false).as_json) - expect(response.parsed_body['subscription'].deep_symbolize_keys).to eq(CustomWizard::ProSubscriptionSerializer.new(@pro.subscription, root: false).as_json) + get "/admin/wizards/subscription.json" + expect(response.parsed_body['server']).to eq(@subscription.server) + expect(response.parsed_body['authentication'].deep_symbolize_keys).to eq(CustomWizard::Subscription::AuthenticationSerializer.new(@subscription.authentication, root: false).as_json) + expect(response.parsed_body['subscription'].deep_symbolize_keys).to eq(CustomWizard::Subscription::SubscriptionSerializer.new(@subscription.subscription, root: false).as_json) end it "#authorize" do - get "/admin/wizards/pro/authorize" + get "/admin/wizards/subscription/authorize" expect(response.status).to eq(302) expect(cookies[:user_api_request_id].present?).to eq(true) end @@ -38,12 +38,12 @@ describe CustomWizard::AdminProController do it "#destroy_authentication" do request_id = SecureRandom.hex(32) payload = generate_payload(request_id, admin_user.id) - @pro.authentication_response(request_id, payload) + @subscription.authentication_response(request_id, payload) - delete "/admin/wizards/pro/authorize.json" + delete "/admin/wizards/subscription/authorize.json" expect(response.status).to eq(200) - expect(CustomWizard::Pro.authorized?).to eq(false) + expect(CustomWizard::Subscription.authorized?).to eq(false) end context "subscription" do @@ -54,18 +54,18 @@ describe CustomWizard::AdminProController do it "handles authentication response and the updates subscription" do request_id = cookies[:user_api_request_id] = SecureRandom.hex(32) payload = generate_payload(request_id, admin_user.id) - get "/admin/wizards/pro/authorize/callback", params: { payload: payload } + get "/admin/wizards/subscription/authorize/callback", params: { payload: payload } - expect(response).to redirect_to("/admin/wizards/pro") - expect(CustomWizard::Pro.subscribed?).to eq(true) + expect(response).to redirect_to("/admin/wizards/subscription") + expect(CustomWizard::Subscription.subscribed?).to eq(true) end it "updates the subscription" do - authenticate_pro - post "/admin/wizards/pro/subscription.json" + authenticate_subscription + post "/admin/wizards/subscription.json" expect(response.status).to eq(200) - expect(CustomWizard::Pro.subscribed?).to eq(true) + expect(CustomWizard::Subscription.subscribed?).to eq(true) end end end diff --git a/spec/requests/custom_wizard/custom_field_extensions_spec.rb b/spec/requests/custom_wizard/custom_field_extensions_spec.rb index 9ec3f5b1..775e3ee0 100644 --- a/spec/requests/custom_wizard/custom_field_extensions_spec.rb +++ b/spec/requests/custom_wizard/custom_field_extensions_spec.rb @@ -9,7 +9,7 @@ describe "custom field extensions" do let!(:user) { Fabricate(:user) } let!(:group) { Fabricate(:group, users: [user]) } let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") } - let(:pro_custom_field_json) { get_wizard_fixture("custom_field/pro_custom_fields") } + let(:subscription_custom_field_json) { get_wizard_fixture("custom_field/subscription_custom_fields") } before do custom_field_json['custom_fields'].each do |field_json| @@ -38,11 +38,11 @@ describe "custom field extensions" do expect(response.parsed_body['post_field_1']).to eq(7) end - context "with a pro subscription" do + context "with a subscription" do before do enable_subscription - pro_custom_field_json['custom_fields'].each do |field_json| + subscription_custom_field_json['custom_fields'].each do |field_json| custom_field = CustomWizard::CustomField.new(nil, field_json) custom_field.save end diff --git a/spec/requests/custom_wizard/steps_controller_spec.rb b/spec/requests/custom_wizard/steps_controller_spec.rb index d4ad4042..8396135c 100644 --- a/spec/requests/custom_wizard/steps_controller_spec.rb +++ b/spec/requests/custom_wizard/steps_controller_spec.rb @@ -119,7 +119,7 @@ describe CustomWizard::StepsController do expect(response.parsed_body['final']).to eq(true) end - context "pro" do + context "subscription" do before do enable_subscription end @@ -149,6 +149,38 @@ describe CustomWizard::StepsController do expect(response.parsed_body['wizard']['start']).to eq("step_3") end + it "returns the correct final step when the conditional final step and last step are the same" do + new_template = wizard_template.dup + new_template['steps'][0]['condition'] = user_condition_template['condition'] + new_template['steps'][2]['condition'] = wizard_field_condition_template['condition'] + CustomWizard::Template.save(new_template, skip_jobs: true) + end + + it "raises an error when user cant see the step due to conditions" do + sign_in(user2) + + new_wizard_template = wizard_template.dup + new_wizard_template['steps'][0]['condition'] = user_condition_template['condition'] + CustomWizard::Template.save(new_wizard_template, skip_jobs: true) + + put '/w/super-mega-fun-wizard/steps/step_1.json' + expect(response.status).to eq(403) + end + + it "returns an updated wizard when condition doesnt pass" do + new_template = wizard_template.dup + new_template['steps'][1]['condition'] = wizard_field_condition_template['condition'] + CustomWizard::Template.save(new_template, skip_jobs: true) + + put '/w/super-mega-fun-wizard/steps/step_1.json', params: { + fields: { + step_1_field_1: "Condition wont pass" + } + } + expect(response.status).to eq(200) + expect(response.parsed_body['wizard']['start']).to eq("step_3") + end + it "returns the correct final step when the conditional final step and last step are the same" do new_template = wizard_template.dup new_template['steps'][0]['condition'] = user_condition_template['condition'] diff --git a/spec/serializers/custom_wizard/notice_serializer_spec.rb b/spec/serializers/custom_wizard/notice_serializer_spec.rb new file mode 100644 index 00000000..5184d890 --- /dev/null +++ b/spec/serializers/custom_wizard/notice_serializer_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require_relative '../../plugin_helper' + +describe CustomWizard::NoticeSerializer do + before do + @notice = CustomWizard::Notice.new( + message: "Message about subscription", + type: "info", + created_at: Time.now - 3.day, + expired_at: nil + ) + @notice.save + end + + it 'should return notice attributes' do + serialized_notice = described_class.new(@notice) + expect(serialized_notice.message).to eq(@notice.message) + expect(serialized_notice.type).to eq(CustomWizard::Notice.types.key(@notice.type)) + expect(serialized_notice.dismissable).to eq(true) + end +end diff --git a/spec/serializers/custom_wizard/pro_serializer_spec.rb b/spec/serializers/custom_wizard/pro_serializer_spec.rb deleted file mode 100644 index 45c1956e..00000000 --- a/spec/serializers/custom_wizard/pro_serializer_spec.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -require_relative '../../plugin_helper' - -describe CustomWizard::ProSerializer do - it 'should return pro attributes' do - pro = CustomWizard::Pro.new - serialized = described_class.new(pro, root: false) - - expect(serialized.server).to eq(pro.server) - expect(serialized.authentication.class).to eq(CustomWizard::ProAuthentication) - expect(serialized.subscription.class).to eq(CustomWizard::ProSubscription) - end -end diff --git a/spec/serializers/custom_wizard/pro/authentication_serializer_spec.rb b/spec/serializers/custom_wizard/subscription/authentication_serializer_spec.rb similarity index 60% rename from spec/serializers/custom_wizard/pro/authentication_serializer_spec.rb rename to spec/serializers/custom_wizard/subscription/authentication_serializer_spec.rb index 53dd74c2..ac29f95a 100644 --- a/spec/serializers/custom_wizard/pro/authentication_serializer_spec.rb +++ b/spec/serializers/custom_wizard/subscription/authentication_serializer_spec.rb @@ -2,11 +2,11 @@ require_relative '../../../plugin_helper' -describe CustomWizard::ProAuthenticationSerializer do +describe CustomWizard::Subscription::AuthenticationSerializer do fab!(:user) { Fabricate(:user) } - it 'should return pro authentication attributes' do - auth = CustomWizard::ProAuthentication.new(OpenStruct.new(key: '1234', auth_at: Time.now, auth_by: user.id)) + it 'should return subscription authentication attributes' do + auth = CustomWizard::Subscription::Authentication.new(OpenStruct.new(key: '1234', auth_at: Time.now, auth_by: user.id)) serialized = described_class.new(auth, root: false).as_json expect(serialized[:active]).to eq(true) diff --git a/spec/serializers/custom_wizard/pro/subscription_serializer_spec.rb b/spec/serializers/custom_wizard/subscription/subscription_serializer_spec.rb similarity index 57% rename from spec/serializers/custom_wizard/pro/subscription_serializer_spec.rb rename to spec/serializers/custom_wizard/subscription/subscription_serializer_spec.rb index a775863e..63caf363 100644 --- a/spec/serializers/custom_wizard/pro/subscription_serializer_spec.rb +++ b/spec/serializers/custom_wizard/subscription/subscription_serializer_spec.rb @@ -2,9 +2,9 @@ require_relative '../../../plugin_helper' -describe CustomWizard::ProSubscriptionSerializer do - it 'should return pro subscription attributes' do - sub = CustomWizard::ProSubscription.new(OpenStruct.new(type: 'community', updated_at: Time.now)) +describe CustomWizard::Subscription::SubscriptionSerializer do + it 'should return subscription attributes' do + sub = CustomWizard::Subscription::Subscription.new(OpenStruct.new(type: 'community', updated_at: Time.now)) serialized = described_class.new(sub, root: false).as_json expect(serialized[:active]).to eq(true) diff --git a/spec/serializers/custom_wizard/subscription_serializer_spec.rb b/spec/serializers/custom_wizard/subscription_serializer_spec.rb new file mode 100644 index 00000000..c6ea0ef2 --- /dev/null +++ b/spec/serializers/custom_wizard/subscription_serializer_spec.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require_relative '../../plugin_helper' + +describe CustomWizard::SubscriptionSerializer do + it 'should return subscription attributes' do + subscription = CustomWizard::Subscription.new + serialized = described_class.new(subscription, root: false) + + expect(serialized.server).to eq(subscription.server) + expect(serialized.authentication.class).to eq(CustomWizard::Subscription::Authentication) + expect(serialized.subscription.class).to eq(CustomWizard::Subscription::Subscription) + end +end