0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-11-22 09:20:29 +01:00
Dieser Commit ist enthalten in:
angusmcleod 2021-09-24 17:58:42 +08:00
Ursprung 270d3bccf5
Commit 084c6f4a7a
94 geänderte Dateien mit 1228 neuen und 413 gelöschten Zeilen

Datei anzeigen

@ -6,20 +6,20 @@ import I18n from "I18n";
const klasses = ["topic", "post", "group", "category"]; const klasses = ["topic", "post", "group", "category"];
const types = ["string", "boolean", "integer", "json"]; const types = ["string", "boolean", "integer", "json"];
const proTypes = { const subscriptionTypes = {
klass: ["group", "category"], klass: ["group", "category"],
type: ["json"], type: ["json"],
}; };
const generateContent = function (array, type, proSubscribed = false) { const generateContent = function (array, type, subscribed = false) {
return array.reduce((result, key) => { return array.reduce((result, key) => {
let proArr = proTypes[type]; let subArr = subscriptionTypes[type];
let pro = proArr && proArr.includes(key); let subscription = subArr && subArr.includes(key);
if (!pro || proSubscribed) { if (!subscription || subscribed) {
result.push({ result.push({
id: key, id: key,
name: I18n.t(`admin.wizard.custom_field.${type}.${key}`), name: I18n.t(`admin.wizard.custom_field.${type}.${key}`),
pro, subscription,
}); });
} }
return result; return result;
@ -32,11 +32,11 @@ export default Component.extend({
postSerializers: ["post"], postSerializers: ["post"],
groupSerializers: ["basic_group"], groupSerializers: ["basic_group"],
categorySerializers: ["basic_category"], categorySerializers: ["basic_category"],
klassContent: computed("proSubscribed", function () { klassContent: computed("subscribed", function () {
return generateContent(klasses, "klass", this.proSubscribed); return generateContent(klasses, "klass", this.subscribed);
}), }),
typeContent: computed("proSubscribed", function () { typeContent: computed("subscribed", function () {
return generateContent(types, "type", this.proSubscribed); return generateContent(types, "type", this.subscribed);
}), }),
showInputs: or("field.new", "field.edit"), showInputs: or("field.new", "field.edit"),
classNames: ["custom-field-input"], classNames: ["custom-field-input"],
@ -54,7 +54,7 @@ export default Component.extend({
const serializers = this.get(`${klass}Serializers`); const serializers = this.get(`${klass}Serializers`);
if (serializers) { if (serializers) {
return generateContent(serializers, "serializers", this.proSubscribed); return generateContent(serializers, "serializers", this.subscribed);
} else { } else {
return []; return [];
} }

Datei anzeigen

@ -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`;
}
})

Datei anzeigen

@ -94,15 +94,15 @@ export default Component.extend(UndoChanges, {
return apis.find((a) => a.name === api).endpoints; return apis.find((a) => a.name === api).endpoints;
}, },
@discourseComputed("proSubscribed") @discourseComputed("subscribed")
actionTypes(proSubscribed) { actionTypes(subscribed) {
return Object.keys(wizardSchema.action.types).reduce((result, type) => { return Object.keys(wizardSchema.action.types).reduce((result, type) => {
let pro = wizardSchema.action.proTypes.includes(type); let subscription = wizardSchema.action.subscriptionTypes.includes(type);
if (proSubscribed || !pro) { if (subscribed || !subscription) {
result.push({ result.push({
id: type, id: type,
name: I18n.t(`admin.wizard.action.${type}.label`), name: I18n.t(`admin.wizard.action.${type}.label`),
pro, subscription,
}); });
} }
return result; return result;

Datei anzeigen

@ -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);
});
}
}
});

Datei anzeigen

@ -6,7 +6,7 @@ import discourseComputed from "discourse-common/utils/decorators";
import I18n from "I18n"; import I18n from "I18n";
export default Component.extend({ export default Component.extend({
classNames: ["realtime-validations", "setting", "full", "pro"], classNames: ["realtime-validations", "setting", "full", "subscription"],
@discourseComputed @discourseComputed
timeUnits() { timeUnits() {

Datei anzeigen

@ -1,18 +1,18 @@
import SingleSelectComponent from "select-kit/components/single-select"; import SingleSelectComponent from "select-kit/components/single-select";
export default SingleSelectComponent.extend({ export default SingleSelectComponent.extend({
classNames: ["combo-box", "wizard-pro-selector"], classNames: ["combo-box", "wizard-subscription-selector"],
selectKitOptions: { selectKitOptions: {
autoFilterable: false, autoFilterable: false,
filterable: false, filterable: false,
showFullTitle: true, showFullTitle: true,
headerComponent: "wizard-pro-selector/wizard-pro-selector-header", headerComponent: "wizard-subscription-selector/wizard-subscription-selector-header",
caretUpIcon: "caret-up", caretUpIcon: "caret-up",
caretDownIcon: "caret-down", caretDownIcon: "caret-down",
}, },
modifyComponentForRow() { modifyComponentForRow() {
return "wizard-pro-selector/wizard-pro-selector-row"; return "wizard-subscription-selector/wizard-subscription-selector-row";
}, },
}); });

Datei anzeigen

@ -3,7 +3,7 @@ import { computed } from "@ember/object";
import { reads } from "@ember/object/computed"; import { reads } from "@ember/object/computed";
export default SingleSelectHeaderComponent.extend({ 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"), caretUpIcon: reads("selectKit.options.caretUpIcon"),
caretDownIcon: reads("selectKit.options.caretDownIcon"), caretDownIcon: reads("selectKit.options.caretDownIcon"),
caretIcon: computed( caretIcon: computed(

Datei anzeigen

@ -1,12 +1,12 @@
import Component from "@ember/component"; 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 { notEmpty } from "@ember/object/computed";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import I18n from "I18n"; import I18n from "I18n";
export default Component.extend({ export default Component.extend({
classNameBindings: [ classNameBindings: [
":custom-wizard-pro-subscription", ":custom-wizard-subscription",
"subscription.active:active:inactive", "subscription.active:active:inactive",
], ],
subscribed: notEmpty("subscription"), subscribed: notEmpty("subscription"),
@ -14,8 +14,8 @@ export default Component.extend({
@discourseComputed("subscription.type") @discourseComputed("subscription.type")
title(type) { title(type) {
return type return type
? I18n.t(`admin.wizard.pro.subscription.title.${type}`) ? I18n.t(`admin.wizard.subscription.subscription.title.${type}`)
: I18n.t("admin.wizard.pro.not_subscribed"); : I18n.t("admin.wizard.subscription.not_subscribed");
}, },
@discourseComputed("subscription.active") @discourseComputed("subscription.active")
@ -25,13 +25,13 @@ export default Component.extend({
@discourseComputed("stateClass") @discourseComputed("stateClass")
stateLabel(stateClass) { stateLabel(stateClass) {
return I18n.t(`admin.wizard.pro.subscription.status.${stateClass}`); return I18n.t(`admin.wizard.subscription.subscription.status.${stateClass}`);
}, },
actions: { actions: {
update() { update() {
this.set("updating", true); this.set("updating", true);
CustomWizardPro.update_subscription() CustomWizardSubscription.update()
.then((result) => { .then((result) => {
if (result.success) { if (result.success) {
this.setProperties({ this.setProperties({

Datei anzeigen

@ -0,0 +1,3 @@
{{#if wizardWarningNotice}}
{{wizard-notice notice=wizardWarningNotice}}
{{/if}}

Datei anzeigen

@ -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);
}
}
}

Datei anzeigen

@ -1,3 +1,7 @@
{{#if currentUser.admin}} {{#if currentUser.admin}}
{{nav-item route="adminWizards" label="admin.wizard.nav_label"}} {{nav-item route="adminWizards" label="admin.wizard.nav_label"}}
{{#if wizardErrorNotice}}
{{d-icon "exclaimation-circle"}}
{{/if}}
{{/if}} {{/if}}

Datei anzeigen

@ -1,6 +1,6 @@
import Controller from "@ember/controller"; import Controller from "@ember/controller";
import discourseComputed from "discourse-common/utils/decorators"; 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"; import { alias } from "@ember/object/computed";
export default Controller.extend({ export default Controller.extend({

Datei anzeigen

@ -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);
}
}
});

Datei anzeigen

@ -59,8 +59,8 @@ export default {
resetNamespace: true, resetNamespace: true,
}); });
this.route("adminWizardsPro", { this.route("adminWizardsSubscription", {
path: "/pro", path: "/subscription",
resetNamespace: true, resetNamespace: true,
}); });
} }

Datei anzeigen

@ -1,4 +1,8 @@
import DiscourseURL from "discourse/lib/url"; 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 { export default {
name: "custom-wizard-edits", name: "custom-wizard-edits",
@ -16,5 +20,29 @@ export default {
} }
return existing.apply(this, [path, opts]); 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);
}
});
});
}, },
}; };

Datei anzeigen

@ -193,6 +193,14 @@ const action = {
"members_visibility_level", "members_visibility_level",
], ],
required: ["id", "type"], required: ["id", "type"],
subscriptionTypes: [
"send_message",
"add_to_group",
"create_category",
"create_group",
"send_to_api",
],
required: ["id", "type"],
proTypes: [ proTypes: [
"send_message", "send_message",
"add_to_group", "add_to_group",

Datei anzeigen

@ -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;

Datei anzeigen

@ -2,11 +2,11 @@ import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error"; import { popupAjaxError } from "discourse/lib/ajax-error";
import EmberObject from "@ember/object"; 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() { status() {
return ajax(basePath, { return ajax(basePath, {
type: "GET", type: "GET",
@ -23,11 +23,11 @@ CustomWizardPro.reopenClass({
}).catch(popupAjaxError); }).catch(popupAjaxError);
}, },
update_subscription() { update() {
return ajax(`${basePath}/subscription`, { return ajax(basePath, {
type: "POST", type: "POST",
}).catch(popupAjaxError); }).catch(popupAjaxError);
}, },
}); });
export default CustomWizardPro; export default CustomWizardSubscription;

Datei anzeigen

@ -9,11 +9,11 @@ export default DiscourseRoute.extend({
setupController(controller, model) { setupController(controller, model) {
const customFields = A(model.custom_fields || []); const customFields = A(model.custom_fields || []);
const proSubscribed = model.pro_subscribed; const subscribed = model.subscribed;
controller.setProperties({ controller.setProperties({
customFields, customFields,
proSubscribed, subscribed,
}); });
}, },
}); });

Datei anzeigen

@ -1,9 +1,9 @@
import CustomWizardPro from "../models/custom-wizard-pro"; import CustomWizardSubscription from "../models/custom-wizard-subscription";
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
model() { model() {
return CustomWizardPro.status(); return CustomWizardSubscription.status();
}, },
setupController(controller, model) { setupController(controller, model) {
@ -13,7 +13,7 @@ export default DiscourseRoute.extend({
actions: { actions: {
authorize() { authorize() {
CustomWizardPro.authorize(); CustomWizardSubscription.authorize();
}, },
}, },
}); });

Datei anzeigen

@ -39,7 +39,7 @@ export default DiscourseRoute.extend({
currentStep: wizard.steps[0], currentStep: wizard.steps[0],
currentAction: wizard.actions[0], currentAction: wizard.actions[0],
creating: model.create, creating: model.create,
proSubscribed: parentModel.pro_subscribed, subscribed: parentModel.subscribed,
}; };
controller.setProperties(props); controller.setProperties(props);

Datei anzeigen

@ -1,9 +1,19 @@
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
import { ajax } from "discourse/lib/ajax";
import { A } from "@ember/array";
export default DiscourseRoute.extend({ 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") { if (transition.targetName === "adminWizards.index") {
this.transitionTo("adminWizardsWizard"); this.transitionTo("adminWizardsWizard");
} }
}, }
}); });

Datei anzeigen

@ -33,7 +33,7 @@
field=field field=field
removeField=(action "removeField") removeField=(action "removeField")
saveField=(action "saveField") saveField=(action "saveField")
proSubscribed=proSubscribed}} subscribed=subscribed}}
{{/each}} {{/each}}
</tbody> </tbody>
</table> </table>

Datei anzeigen

@ -1,34 +0,0 @@
<div class="admin-wizard-controls">
<h3>{{i18n "admin.wizard.pro.title"}}</h3>
<div class="buttons">
{{#if model.authentication.active}}
{{conditional-loading-spinner size="small" condition=unauthorizing}}
<a {{action "unauthorize"}} title={{i18n "admin.wizard.pro.unauthorize"}} role="button">
{{i18n "admin.wizard.pro.unauthorize"}}
</a>
<label title={{i18n "admin.wizard.pro.authorized"}}>
{{i18n "admin.wizard.pro.authorized"}}
</label>
{{else}}
{{d-button
icon="id-card"
label="admin.wizard.pro.authorize"
title="admin.wizard.pro.authorize"
action=(route-action "authorize")}}
{{/if}}
</div>
</div>
{{wizard-message
key=messageKey
url=messageUrl
type=messageType
opts=messageOpts
component="pro"}}
<div class="admin-wizard-container">
{{#if showSubscription}}
{{wizard-pro-subscription subscription=model.subscription}}
{{/if}}
</div>

Datei anzeigen

@ -0,0 +1,35 @@
<div class="admin-wizard-controls">
<h3>{{i18n "admin.wizard.subscription.title"}}</h3>
<div class="buttons">
{{#if model.authentication.active}}
{{conditional-loading-spinner size="small" condition=unauthorizing}}
<a {{action "unauthorize"}} title={{i18n "admin.wizard.subscription.unauthorize"}} role="button">
{{i18n "admin.wizard.subscription.unauthorize"}}
</a>
<label title={{i18n "admin.wizard.subscription.authorized"}}>
{{i18n "admin.wizard.subscription.authorized"}}
</label>
{{else}}
{{d-button
icon="id-card"
class="btn-primary"
label="admin.wizard.subscription.authorize"
title="admin.wizard.subscription.authorize"
action=(route-action "authorize")}}
{{/if}}
</div>
</div>
{{wizard-message
key=messageKey
url=messageUrl
type=messageType
opts=messageOpts
component="subscription"}}
<div class="admin-wizard-container">
{{#if showSubscription}}
{{wizard-subscription subscription=model.subscription}}
{{/if}}
</div>

Datei anzeigen

@ -126,11 +126,10 @@
</div> </div>
</div> </div>
{{#if proSubscribed}} {{#subscription-container subscribed=subscribed}}
<div class="setting pro"> <div class="setting">
<div class="setting-label"> <div class="setting-label">
<label>{{i18n "admin.wizard.save_submissions"}}</label> <label>{{i18n "admin.wizard.save_submissions"}}</label>
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
</div> </div>
<div class="setting-value"> <div class="setting-value">
{{input type="checkbox" checked=wizard.save_submissions}} {{input type="checkbox" checked=wizard.save_submissions}}
@ -138,17 +137,16 @@
</div> </div>
</div> </div>
<div class="setting pro"> <div class="setting">
<div class="setting-label"> <div class="setting-label">
<label>{{i18n "admin.wizard.restart_on_revisit"}}</label> <label>{{i18n "admin.wizard.restart_on_revisit"}}</label>
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
</div> </div>
<div class="setting-value"> <div class="setting-value">
{{input type="checkbox" checked=wizard.restart_on_revisit}} {{input type="checkbox" checked=wizard.restart_on_revisit}}
<span>{{i18n "admin.wizard.restart_on_revisit_label"}}</span> <span>{{i18n "admin.wizard.restart_on_revisit_label"}}</span>
</div> </div>
</div> </div>
{{/if}} {{/subscription-container}}
</div> </div>
{{wizard-links {{wizard-links
@ -163,7 +161,7 @@
currentField=currentField currentField=currentField
wizardFields=wizardFields wizardFields=wizardFields
fieldTypes=fieldTypes fieldTypes=fieldTypes
proSubscribed=proSubscribed}} subscribed=subscribed}}
{{/if}} {{/if}}
{{wizard-links {{wizard-links
@ -180,7 +178,7 @@
apis=apis apis=apis
removeAction="removeAction" removeAction="removeAction"
wizardFields=wizardFields wizardFields=wizardFields
proSubscribed=proSubscribed}} subscribed=subscribed}}
{{/each}} {{/each}}
<div class="admin-wizard-buttons"> <div class="admin-wizard-buttons">

Datei anzeigen

@ -7,13 +7,18 @@
{{/if}} {{/if}}
{{nav-item route="adminWizardsLogs" label="admin.wizard.log.nav_label"}} {{nav-item route="adminWizardsLogs" label="admin.wizard.log.nav_label"}}
{{nav-item route="adminWizardsManager" label="admin.wizard.manager.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"}}
<div class="admin-actions"> <div class="admin-actions">
<a target="_blank" class="btn btn-pavilion-pro" rel="noreferrer noopener" href="https://thepavilion.io/w/support" title={{i18n "admin.wizard.pro_support_button.title"}}>{{d-icon "far-life-ring"}}{{i18n "admin.wizard.pro_support_button.label"}}</a> <a target="_blank" class="btn btn-pavilion-support" rel="noreferrer noopener" href="https://thepavilion.io/w/support" title={{i18n "admin.wizard.support_button.title"}}>
{{d-icon "far-life-ring"}}{{i18n "admin.wizard.support_button.label"}}
</a>
</div> </div>
{{/admin-nav}} {{/admin-nav}}
<div class="admin-container"> <div class="admin-container">
{{#each notices as |notice|}}
{{wizard-notice notice=notice}}
{{/each}}
{{outlet}} {{outlet}}
</div> </div>

Datei anzeigen

@ -1,13 +1,13 @@
{{#if showInputs}} {{#if showInputs}}
<td> <td>
{{wizard-pro-selector {{wizard-subscription-selector
value=field.klass value=field.klass
content=klassContent content=klassContent
none="admin.wizard.custom_field.klass.select" none="admin.wizard.custom_field.klass.select"
onChange=(action (mut field.klass))}} onChange=(action (mut field.klass))}}
</td> </td>
<td> <td>
{{wizard-pro-selector {{wizard-subscription-selector
value=field.type value=field.type
content=typeContent content=typeContent
none="admin.wizard.custom_field.type.select" none="admin.wizard.custom_field.type.select"

Datei anzeigen

@ -0,0 +1,12 @@
<div class=subscription-header>
<h3>{{i18n 'admin.wizard.subscription_container.title'}}</h3>
<a href="/admin/wizards/subscription" title={{i18n subscribedTitle}}>
{{d-icon subscribedIcon}}
{{i18n subscribedLabel}}
</a>
</div>
<div class="subscription-settings">
{{yield}}
</div>

Datei anzeigen

@ -12,7 +12,7 @@
</div> </div>
<div class="setting-value"> <div class="setting-value">
{{wizard-pro-selector {{wizard-subscription-selector
value=action.type value=action.type
content=actionTypes content=actionTypes
onChange=(action "changeType") onChange=(action "changeType")

Datei anzeigen

@ -207,11 +207,10 @@
</div> </div>
{{/if}} {{/if}}
{{#if proSubscribed}} {{#subscription-container subscribed=subscribed}}
<div class="setting full field-mapper-setting pro"> <div class="setting full field-mapper-setting">
<div class="setting-label"> <div class="setting-label">
<label>{{i18n "admin.wizard.condition"}}</label> <label>{{i18n "admin.wizard.condition"}}</label>
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
</div> </div>
<div class="setting-value"> <div class="setting-value">
@ -221,10 +220,9 @@
</div> </div>
</div> </div>
<div class="setting full field-mapper-setting pro"> <div class="setting full field-mapper-setting">
<div class="setting-label"> <div class="setting-label">
<label>{{i18n "admin.wizard.index"}}</label> <label>{{i18n "admin.wizard.index"}}</label>>
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
</div> </div>
<div class="setting-value"> <div class="setting-value">
@ -256,4 +254,4 @@
{{#if validations}} {{#if validations}}
{{wizard-realtime-validations field=field validations=validations}} {{wizard-realtime-validations field=field validations=validations}}
{{/if}} {{/if}}
{{/if}} {{/subscription-container}}

Datei anzeigen

@ -33,11 +33,10 @@
</div> </div>
</div> </div>
{{#if proSubscribed}} {{#subscription-container subscribed=subscribed}}
<div class="setting full field-mapper-setting pro"> <div class="setting full field-mapper-setting">
<div class="setting-label"> <div class="setting-label">
<label>{{i18n "admin.wizard.condition"}}</label> <label>{{i18n "admin.wizard.condition"}}</label>
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
</div> </div>
<div class="setting-value"> <div class="setting-value">
@ -83,10 +82,9 @@
</div> </div>
</div> </div>
<div class="setting full field-mapper-setting pro"> <div class="setting full field-mapper-setting">
<div class="setting-label"> <div class="setting-label">
<label>{{i18n "admin.wizard.step.permitted_params.label"}}</label> <label>{{i18n "admin.wizard.step.permitted_params.label"}}</label>
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
</div> </div>
<div class="setting-value"> <div class="setting-value">
{{wizard-mapper {{wizard-mapper
@ -100,7 +98,7 @@
)}} )}}
</div> </div>
</div> </div>
{{/if}} {{/subscription-container}}
{{wizard-links {{wizard-links
itemType="field" itemType="field"
@ -116,5 +114,5 @@
fieldTypes=fieldTypes fieldTypes=fieldTypes
removeField="removeField" removeField="removeField"
wizardFields=wizardFields wizardFields=wizardFields
proSubscribed=proSubscribed}} subscribed=subscribed}}
{{/each}} {{/each}}

Datei anzeigen

@ -0,0 +1,37 @@
<div class="notice-header">
{{#if resolved}}
<div class="notice-expired-at notice-badge" title={{notice.expired_at}}>
{{d-icon "check"}}
<span class="notice-resolved">{{i18n "admin.wizard.notice.resolved"}}</span>
{{format-date notice.expired_at leaveAgo="true"}}
</div>
{{/if}}
<div class="notice-title notice-badge" title={{title}}>
{{d-icon icon}}
<span>{{title}}</span>
</div>
<div class="notice-created-at notice-badge" title={{notice.created_at}}>
{{d-icon "calendar-alt"}}
<span class="notice-issued">{{i18n "admin.wizard.notice.issued"}}</span>
{{format-date notice.created_at leaveAgo="true"}}
</div>
<div class="notice-plugin notice-badge" title={{i18n "admin.wizard.notice.plugin"}}>
{{d-icon "plug"}}
<span>{{i18n "admin.wizard.notice.plugin"}}</span>
</div>
</div>
<div class="notice-message">
{{{notice.message}}}
</div>
{{#if canDismiss}}
{{#if dismissing}}
{{loading-spinner size="small"}}
{{else}}
<a {{action "dismiss"}} role="button" class="dismiss-notice">{{d-icon "times"}}</a>
{{/if}}
{{/if}}

Datei anzeigen

@ -1,6 +1,5 @@
<div class="setting-label"> <div class="setting-label">
<label>{{i18n "admin.wizard.field.validations.header"}}</label> <label>{{i18n "admin.wizard.field.validations.header"}}</label>
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
</div> </div>
<div class="setting-value full"> <div class="setting-value full">
<ul> <ul>

Datei anzeigen

@ -7,8 +7,8 @@
shouldDisplayClearableButton=shouldDisplayClearableButton shouldDisplayClearableButton=shouldDisplayClearableButton
}} }}
{{#if selectedContent.pro}} {{#if selectedContent.subscription}}
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span> <span class="subscription-label">{{i18n "admin.wizard.subscription.label"}}</span>
{{/if}} {{/if}}
{{d-icon caretIcon class="caret-icon"}} {{d-icon caretIcon class="caret-icon"}}

Datei anzeigen

@ -9,7 +9,7 @@
<div class="texts"> <div class="texts">
<span class="name">{{html-safe label}}</span> <span class="name">{{html-safe label}}</span>
{{#if item.pro}} {{#if item.subscription}}
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span> <span class="subscription-label">{{i18n "admin.wizard.subscription.label"}}</span>
{{/if}} {{/if}}
</div> </div>

Datei anzeigen

@ -13,8 +13,8 @@
icon="sync" icon="sync"
action=(action "update") action=(action "update")
disabled=updating disabled=updating
title="admin.wizard.pro.subscription.update" title="admin.wizard.subscription.subscription.update"
label="admin.wizard.pro.subscription.update"}} label="admin.wizard.subscription.subscription.update"}}
</div> </div>
</div> </div>
@ -24,7 +24,7 @@
{{#if subscription.updated_at}} {{#if subscription.updated_at}}
<div class="subscription-updated-at" title={{subscription.updated_at}}> <div class="subscription-updated-at" title={{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"}}
</div> </div>
{{/if}} {{/if}}
</div> </div>

Datei anzeigen

@ -1,8 +1,8 @@
@import "wizard-mapper"; @import "wizard/mapper";
@import "wizard-manager"; @import "wizard/manager";
@import "wizard-api"; @import "wizard/api";
@import "common/components/buttons"; @import "common/components/buttons";
@import "wizard-variables"; @import "wizard/variables";
.admin-wizard-controls { .admin-wizard-controls {
display: flex; display: flex;
@ -121,7 +121,7 @@
} }
.wizard-settings-parent { .wizard-settings-parent {
padding: 20px; padding: 1em;
border: 1px solid var(--primary-low); border: 1px solid var(--primary-low);
} }
@ -142,7 +142,7 @@
.wizard-basic-details, .wizard-basic-details,
.wizard-custom-field, .wizard-custom-field,
.advanced-settings { .subscription-settings {
@extend .wizard-settings-group; @extend .wizard-settings-group;
} }
@ -411,7 +411,7 @@
margin-top: 5px; margin-top: 5px;
} }
&.pro { &.subscription {
.setting-label { .setting-label {
display: flex; display: flex;
flex-direction: column; 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 { .wizard-custom-action > [class~="setting"]:first-of-type {
margin-bottom: 0; margin-bottom: 0;
} }
@ -735,7 +726,7 @@
flex-wrap: wrap; flex-wrap: wrap;
> li { > li {
background-color: var(--primary-low); border: 1px solid var(--primary);
padding: 1em; padding: 1em;
margin: 0 0 1em 0; margin: 0 0 1em 0;
@ -797,12 +788,12 @@
vertical-align: middle; vertical-align: middle;
} }
.pro-label { .subscription-label {
color: var(--tertiary); color: var(--tertiary);
font-size: 0.75em; font-size: 0.75em;
} }
.admin-wizards-pro { .admin-wizards-subscription {
.admin-wizard-controls { .admin-wizard-controls {
h3, h3,
label { label {
@ -826,7 +817,7 @@
} }
} }
.custom-wizard-pro-subscription { .custom-wizard-subscription {
.title-container { .title-container {
display: flex; display: flex;
justify-content: space-between; 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 { .select-kit-row .texts {
display: flex; display: flex;
align-items: center; align-items: center;
} }
.pro-label { .subscription-label {
margin-left: 0.75em; margin-left: 0.75em;
padding-top: 0.25em; padding-top: 0.25em;
} }
} }
.btn.btn-pavilion-pro { .btn.btn-pavilion-support {
background: var(--pavilion-primary); background: var(--pavilion-primary);
color: var(--pavilion-secondary); color: var(--pavilion-secondary);
@ -883,11 +874,108 @@
&:hover, &:hover,
&:focus { &:focus {
background: darken($pavilionPrimary, 5%); background: darken($pavilion_primary, 5%);
&[href], &[href],
svg.d-icon { 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);
}
}

Datei anzeigen

@ -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};
}

Datei anzeigen

@ -1,7 +0,0 @@
$pavilionPrimary: #3c1c8c;
$pavilionSecondary: #ffffff;
:root {
--pavilion-primary: #3c1c8c;
--pavilion-secondary: #ffffff;
}

Datei anzeigen

@ -60,9 +60,9 @@ en:
expand_text: "Read More" expand_text: "Read More"
collapse_text: "Show Less" collapse_text: "Show Less"
pro_support_button: support_button:
title: "Request Pro Support" title: "Request Support"
label: "Pro Support" label: "Support"
message: message:
wizard: wizard:
@ -95,10 +95,10 @@ en:
destroying: Destroying wizards... destroying: Destroying wizards...
import_complete: Import complete import_complete: Import complete
destroy_complete: Destruction complete destroy_complete: Destruction complete
pro: subscription:
documentation: Check out the PRO documentation documentation: Check out the subscription documentation
authorize: "Authorize this forum to use your PRO subscription plan on %{server}." 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 PRO 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_expiring: "Your subscription is active, but will expire in the next 48 hours."
subscription_active: "Your subscription is active." subscription_active: "Your subscription is active."
subscription_inactive: "Your subscription is inactive on this forum. Read more in <a href='https://thepavilion.io/t/3652'>the documentation</a>." subscription_inactive: "Your subscription is inactive on this forum. Read more in <a href='https://thepavilion.io/t/3652'>the documentation</a>."
@ -455,10 +455,19 @@ en:
destroy: Destroy destroy: Destroy
destroyed: destroyed destroyed: destroyed
pro: subscription_container:
nav_label: PRO title: Subscriber Features
label: PRO subscribed:
title: Custom Wizard PRO 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 authorize: Authorize
authorized: Authorized authorized: Authorized
unauthorize: cancel unauthorize: cancel
@ -471,7 +480,14 @@ en:
active: Active active: Active
inactive: Inactive inactive: Inactive
update: Update 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: wizard_js:
group: group:

Datei anzeigen

@ -17,7 +17,7 @@ en:
name_too_short: "'%{name}' is too short for a custom field name (min length is #{min_length})" 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" name_already_taken: "'%{name}' is already taken as a custom field name"
save_default: "Failed to save 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: field:
too_short: "%{label} must be at least %{min} characters" too_short: "%{label} must be at least %{min} characters"
@ -50,7 +50,16 @@ en:
required: "%{property} is required" required: "%{property} is required"
conflict: "Wizard with id '%{wizard_id}' already exists" conflict: "Wizard with id '%{wizard_id}' already exists"
after_time: "After time setting is invalid" 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 <a href="mailto:support@thepavilion.io">support@thepavilion.io</a> for further assistance.
site_settings: site_settings:
custom_wizard_enabled: "Enable custom wizards." custom_wizard_enabled: "Enable custom wizards."

Datei anzeigen

@ -45,10 +45,13 @@ Discourse::Application.routes.append do
post 'admin/wizards/manager/import' => 'admin_manager#import' post 'admin/wizards/manager/import' => 'admin_manager#import'
delete 'admin/wizards/manager/destroy' => 'admin_manager#destroy' delete 'admin/wizards/manager/destroy' => 'admin_manager#destroy'
get 'admin/wizards/pro' => 'admin_pro#index' get 'admin/wizards/subscription' => 'admin_subscription#index'
get 'admin/wizards/pro/authorize' => 'admin_pro#authorize' post 'admin/wizards/subscription' => 'admin_subscription#update_subscription'
get 'admin/wizards/pro/authorize/callback' => 'admin_pro#authorize_callback' get 'admin/wizards/subscription/authorize' => 'admin_subscription#authorize'
delete 'admin/wizards/pro/authorize' => 'admin_pro#destroy_authentication' get 'admin/wizards/subscription/authorize/callback' => 'admin_subscription#authorize_callback'
post 'admin/wizards/pro/subscription' => 'admin_pro#update_subscription' 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
end end

Datei anzeigen

@ -3,6 +3,12 @@ class CustomWizard::AdminController < ::Admin::AdminController
before_action :ensure_admin before_action :ensure_admin
def index def index
render_json_dump(
notices: ActiveModel::ArraySerializer.new(
CustomWizard::Notice.list,
each_serializer: CustomWizard::NoticeSerializer
)
)
end end
private private

Datei anzeigen

@ -3,7 +3,7 @@ class CustomWizard::AdminCustomFieldsController < CustomWizard::AdminController
def index def index
render_json_dump( render_json_dump(
custom_fields: custom_field_list, custom_fields: custom_field_list,
pro_subscribed: CustomWizard::Pro.subscribed? subscribed: CustomWizard::Subscription.subscribed?
) )
end end

Datei anzeigen

@ -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

Datei anzeigen

@ -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

Datei anzeigen

@ -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

Datei anzeigen

@ -11,7 +11,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
field_types: CustomWizard::Field.types, field_types: CustomWizard::Field.types,
realtime_validations: CustomWizard::RealtimeValidation.types, realtime_validations: CustomWizard::RealtimeValidation.types,
custom_fields: custom_field_list, custom_fields: custom_field_list,
pro_subscribed: CustomWizard::Pro.subscribed? subscribed: CustomWizard::Subscription.subscribed?
) )
end end

Datei anzeigen

@ -5,7 +5,7 @@ class CustomWizard::WizardController < ::ApplicationController
layout 'wizard' layout 'wizard'
before_action :ensure_plugin_enabled 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_page_title
helper_method :wizard_theme_id helper_method :wizard_theme_id
helper_method :wizard_theme_lookup helper_method :wizard_theme_lookup
@ -84,7 +84,7 @@ class CustomWizard::WizardController < ::ApplicationController
end end
end end
def update_pro_subscription def update_subscription
CustomWizard::Pro.update_subscription CustomWizard::Subscription.update
end end
end end

Datei anzeigen

@ -1,5 +1,5 @@
{ {
"result": { "result": {
"line": 92.14 "line": 92.3
} }
} }

Datei anzeigen

@ -0,0 +1,9 @@
# frozen_string_literal: true
class Jobs::CustomWizardUpdateNotices < ::Jobs::Scheduled
every 5.minutes
def execute(args = {})
CustomWizard::Notice.update
end
end

Datei anzeigen

@ -0,0 +1,9 @@
# frozen_string_literal: true
class Jobs::CustomWizardUpdateSubscription < ::Jobs::Scheduled
every 1.hour
def execute(args = {})
CustomWizard::Subscription.update
end
end

Datei anzeigen

@ -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

Datei anzeigen

@ -749,8 +749,4 @@ class CustomWizard::Action
@log.join('; ') @log.join('; ')
) )
end end
def pro_actions
%w[send_message watch_categories send_to_api create_group create_category]
end
end end

Datei anzeigen

@ -17,9 +17,9 @@ class ::CustomWizard::CustomField
category: ["basic_category"], category: ["basic_category"],
post: ["post"] post: ["post"]
} }
PRO_CLASSES ||= ['category', 'group'] SUBSCRIPTION_CLASSES ||= ['category', 'group']
TYPES ||= ["string", "boolean", "integer", "json"] TYPES ||= ["string", "boolean", "integer", "json"]
PRO_TYPES ||= ["json"] SUBSCRIPTION_TYPES ||= ["json"]
LIST_CACHE_KEY ||= 'custom_field_list' LIST_CACHE_KEY ||= 'custom_field_list'
def self.serializers def self.serializers
@ -40,7 +40,7 @@ class ::CustomWizard::CustomField
end end
end end
@pro = CustomWizard::Pro.new @subscription = CustomWizard::Subscription.new
end end
def save def save
@ -85,8 +85,8 @@ class ::CustomWizard::CustomField
next next
end end
if attr == 'klass' && PRO_CLASSES.include?(value) && !@pro.subscribed? if attr == 'klass' && SUBSCRIPTION_CLASSES.include?(value) && !@subscription.subscribed?
add_error(I18n.t("wizard.custom_field.error.pro_type", type: value)) add_error(I18n.t("wizard.custom_field.error.subscription_type", type: value))
end end
if attr == 'serializers' && (unsupported = value - CLASSES[klass.to_sym]).length > 0 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)) add_error(I18n.t("#{i18n_key}.unsupported_type", type: value))
end end
if attr == 'type' && PRO_TYPES.include?(value) && !@pro.subscribed? if attr == 'type' && SUBSCRIPTION_TYPES.include?(value) && !@subscription.subscribed?
add_error(I18n.t("wizard.custom_field.error.pro_type", type: value)) add_error(I18n.t("wizard.custom_field.error.subscription_type", type: value))
end end
if attr == 'name' if attr == 'name'

Datei anzeigen

@ -47,7 +47,7 @@ class CustomWizard::Mapper
@data = params[:data] || {} @data = params[:data] || {}
@user = params[:user] @user = params[:user]
@opts = params[:opts] || {} @opts = params[:opts] || {}
@pro = CustomWizard::Pro.new @subscription = CustomWizard::Subscription.new
end end
def perform def perform
@ -252,7 +252,7 @@ class CustomWizard::Mapper
end end
end end
if opts[:template] && @pro.subscribed? if opts[:template] && @subscription.subscribed?
template = Liquid::Template.parse(string) template = Liquid::Template.parse(string)
string = template.render(data) string = template.render(data)
end end

234
lib/custom_wizard/notice.rb Normale Datei
Datei anzeigen

@ -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

Datei anzeigen

@ -1,14 +1,14 @@
# frozen_string_literal: true # frozen_string_literal: true
class CustomWizard::Pro class CustomWizard::Subscription
include ActiveModel::Serialization include ActiveModel::Serialization
attr_accessor :authentication, attr_accessor :authentication,
:subscription :subscription
def initialize def initialize
@authentication = CustomWizard::ProAuthentication.new(get_authentication) @authentication = CustomWizard::Subscription::Authentication.new(get_authentication)
@subscription = CustomWizard::ProSubscription.new(get_subscription) @subscription = CustomWizard::Subscription::Subscription.new(get_subscription)
end end
def authorized? def authorized?
@ -35,7 +35,7 @@ class CustomWizard::Pro
"discourse-subscription-server:user_subscription" "discourse-subscription-server:user_subscription"
end end
def update_subscription def update
if @authentication.active? if @authentication.active?
response = Excon.get( response = Excon.get(
"https://#{server}/subscription-server/user-subscriptions/#{subscription_type}/#{client_name}", "https://#{server}/subscription-server/user-subscriptions/#{subscription_type}/#{client_name}",
@ -67,7 +67,7 @@ class CustomWizard::Pro
def destroy_subscription def destroy_subscription
if remove_subscription if remove_subscription
@subscription = CustomWizard::ProSubscription.new(get_subscription) @subscription = CustomWizard::Subscription::Subscription.new(get_subscription)
!@subscription.active? !@subscription.active?
else else
false false
@ -80,7 +80,7 @@ class CustomWizard::Pro
public_key: keys.public_key, public_key: keys.public_key,
nonce: keys.nonce, nonce: keys.nonce,
client_id: @authentication.client_id, 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, application_name: SiteSetting.title,
scopes: scope scopes: scope
} }
@ -108,7 +108,7 @@ class CustomWizard::Pro
def destroy_authentication def destroy_authentication
if remove_authentication if remove_authentication
@authentication = CustomWizard::ProAuthentication.new(get_authentication) @authentication = CustomWizard::Subscription::Authentication.new(get_authentication)
!@authentication.active? !@authentication.active?
else else
false false
@ -123,12 +123,12 @@ class CustomWizard::Pro
self.new.authorized? self.new.authorized?
end end
def self.update_subscription def self.update
self.new.update_subscription self.new.update
end end
def self.namespace def self.namespace
"custom_wizard_pro" "custom_wizard_subscription"
end end
private private
@ -157,8 +157,8 @@ class CustomWizard::Pro
end end
def set_subscription(type) def set_subscription(type)
PluginStore.set(CustomWizard::Pro.namespace, subscription_db_key, type: type, updated_at: Time.now) PluginStore.set(CustomWizard::Subscription.namespace, subscription_db_key, type: type, updated_at: Time.now)
CustomWizard::ProSubscription.new(get_subscription) CustomWizard::Subscription::Subscription.new(get_subscription)
end end
def get_authentication def get_authentication
@ -176,7 +176,7 @@ class CustomWizard::Pro
auth_by: user_id, auth_by: user_id,
auth_at: Time.now auth_at: Time.now
) )
CustomWizard::ProAuthentication.new(get_authentication) CustomWizard::Subscription::Authentication.new(get_authentication)
end end
def remove_authentication def remove_authentication

Datei anzeigen

@ -1,5 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
class CustomWizard::ProAuthentication class CustomWizard::Subscription::Authentication
include ActiveModel::Serialization include ActiveModel::Serialization
attr_reader :client_id, attr_reader :client_id,
@ -53,7 +53,7 @@ class CustomWizard::ProAuthentication
end end
def get_keys(request_id) 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( OpenStruct.new(
user_id: raw && raw['user_id'], user_id: raw && raw['user_id'],
pem: raw && raw['pem'], pem: raw && raw['pem'],
@ -72,7 +72,7 @@ class CustomWizard::ProAuthentication
end end
def set_keys(request_id, user_id, rsa, nonce) 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, user_id: user_id,
pem: rsa.export, pem: rsa.export,
nonce: nonce nonce: nonce
@ -80,16 +80,16 @@ class CustomWizard::ProAuthentication
end end
def delete_keys(request_id) 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 end
def get_client_id def get_client_id
PluginStore.get(CustomWizard::Pro.namespace, client_id_db_key) PluginStore.get(CustomWizard::Subscription.namespace, client_id_db_key)
end end
def set_client_id def set_client_id
client_id = SecureRandom.hex(32) 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 client_id
end end
end end

Datei anzeigen

@ -1,5 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
class CustomWizard::ProSubscription class CustomWizard::Subscription::Subscription
include ActiveModel::Serialization include ActiveModel::Serialization
attr_reader :type, attr_reader :type,

Datei anzeigen

@ -6,7 +6,7 @@ class CustomWizard::TemplateValidator
def initialize(data, opts = {}) def initialize(data, opts = {})
@data = data @data = data
@opts = opts @opts = opts
@pro = CustomWizard::Pro.new @subscription = CustomWizard::Subscription.new
end end
def perform def perform
@ -15,15 +15,15 @@ class CustomWizard::TemplateValidator
check_id(data, :wizard) check_id(data, :wizard)
check_required(data, :wizard) check_required(data, :wizard)
validate_after_time validate_after_time
validate_pro(data, :wizard) validate_subscription(data, :wizard)
data[:steps].each do |step| data[:steps].each do |step|
check_required(step, :step) check_required(step, :step)
validate_pro(step, :step) validate_subscription(step, :step)
if step[:fields].present? if step[:fields].present?
step[:fields].each do |field| step[:fields].each do |field|
validate_pro(field, :field) validate_subscription(field, :field)
check_required(field, :field) check_required(field, :field)
end end
end end
@ -31,7 +31,7 @@ class CustomWizard::TemplateValidator
if data[:actions].present? if data[:actions].present?
data[:actions].each do |action| data[:actions].each do |action|
validate_pro(action, :action) validate_subscription(action, :action)
check_required(action, :action) check_required(action, :action)
end end
end end
@ -52,7 +52,7 @@ class CustomWizard::TemplateValidator
} }
end end
def self.pro def self.subscription
{ {
wizard: { wizard: {
save_submissions: 'false', save_submissions: 'false',
@ -90,18 +90,18 @@ class CustomWizard::TemplateValidator
end end
end end
def validate_pro(object, type) def validate_subscription(object, type)
self.class.pro[type].each do |property, pro_type| self.class.subscription[type].each do |property, subscription_type|
val = object[property.to_s] val = object[property.to_s]
is_pro = (val != nil) && ( is_subscription = (val != nil) && (
pro_type === 'present' && val.present? || subscription_type === 'present' && val.present? ||
(['true', 'false'].include?(pro_type) && cast_bool(val) == cast_bool(pro_type)) || (['true', 'false'].include?(subscription_type) && cast_bool(val) == cast_bool(subscription_type)) ||
(pro_type === 'conditional' && val.is_a?(Hash)) || (subscription_type === 'conditional' && val.is_a?(Hash)) ||
(pro_type.is_a?(Array) && pro_type.include?(val)) (subscription_type.is_a?(Array) && subscription_type.include?(val))
) )
if is_pro && !@pro.subscribed? if is_subscription && !@subscription.subscribed?
errors.add :base, I18n.t("wizard.validation.pro", type: type.to_s, property: property) errors.add :base, I18n.t("wizard.validation.subscription", type: type.to_s, property: property)
end end
end end
end end

Datei anzeigen

@ -7,9 +7,7 @@
# contact emails: angus@thepavilion.io # contact emails: angus@thepavilion.io
gem 'liquid', '5.0.1', require: true gem 'liquid', '5.0.1', require: true
register_asset 'stylesheets/common/wizard-admin.scss' register_asset 'stylesheets/admin/admin.scss', :desktop
register_asset 'stylesheets/common/wizard-mapper.scss'
enabled_site_setting :custom_wizard_enabled enabled_site_setting :custom_wizard_enabled
config = Rails.application.config config = Rails.application.config
@ -42,6 +40,7 @@ if respond_to?(:register_svg_icon)
register_svg_icon "comment-alt" register_svg_icon "comment-alt"
register_svg_icon "far-life-ring" register_svg_icon "far-life-ring"
register_svg_icon "arrow-right" register_svg_icon "arrow-right"
register_svg_icon "shield-virus"
end end
class ::Sprockets::DirectiveProcessor class ::Sprockets::DirectiveProcessor
@ -71,13 +70,15 @@ after_initialize do
../controllers/custom_wizard/admin/logs.rb ../controllers/custom_wizard/admin/logs.rb
../controllers/custom_wizard/admin/manager.rb ../controllers/custom_wizard/admin/manager.rb
../controllers/custom_wizard/admin/custom_fields.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/wizard.rb
../controllers/custom_wizard/steps.rb ../controllers/custom_wizard/steps.rb
../controllers/custom_wizard/realtime_validations.rb ../controllers/custom_wizard/realtime_validations.rb
../jobs/regular/refresh_api_access_token.rb ../jobs/regular/refresh_api_access_token.rb
../jobs/regular/set_after_time_wizard.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/template.rb
../lib/custom_wizard/validators/update.rb ../lib/custom_wizard/validators/update.rb
../lib/custom_wizard/action_result.rb ../lib/custom_wizard/action_result.rb
@ -96,9 +97,10 @@ after_initialize do
../lib/custom_wizard/submission.rb ../lib/custom_wizard/submission.rb
../lib/custom_wizard/template.rb ../lib/custom_wizard/template.rb
../lib/custom_wizard/wizard.rb ../lib/custom_wizard/wizard.rb
../lib/custom_wizard/pro.rb ../lib/custom_wizard/notice.rb
../lib/custom_wizard/pro/subscription.rb ../lib/custom_wizard/subscription.rb
../lib/custom_wizard/pro/authentication.rb ../lib/custom_wizard/subscription/subscription.rb
../lib/custom_wizard/subscription/authentication.rb
../lib/custom_wizard/api/api.rb ../lib/custom_wizard/api/api.rb
../lib/custom_wizard/api/authorization.rb ../lib/custom_wizard/api/authorization.rb
../lib/custom_wizard/api/endpoint.rb ../lib/custom_wizard/api/endpoint.rb
@ -119,9 +121,10 @@ after_initialize do
../serializers/custom_wizard/log_serializer.rb ../serializers/custom_wizard/log_serializer.rb
../serializers/custom_wizard/submission_serializer.rb ../serializers/custom_wizard/submission_serializer.rb
../serializers/custom_wizard/realtime_validation/similar_topics_serializer.rb ../serializers/custom_wizard/realtime_validation/similar_topics_serializer.rb
../serializers/custom_wizard/pro/authentication_serializer.rb ../serializers/custom_wizard/subscription/authentication_serializer.rb
../serializers/custom_wizard/pro/subscription_serializer.rb ../serializers/custom_wizard/subscription/subscription_serializer.rb
../serializers/custom_wizard/pro_serializer.rb ../serializers/custom_wizard/subscription_serializer.rb
../serializers/custom_wizard/notice_serializer.rb
../extensions/extra_locales_controller.rb ../extensions/extra_locales_controller.rb
../extensions/invites_controller.rb ../extensions/invites_controller.rb
../extensions/users_controller.rb ../extensions/users_controller.rb
@ -238,5 +241,11 @@ after_initialize do
"#{serializer_klass}_serializer".classify.constantize.prepend CustomWizardCustomFieldSerializer "#{serializer_klass}_serializer".classify.constantize.prepend CustomWizardCustomFieldSerializer
end 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) DiscourseEvent.trigger(:custom_wizard_ready)
end end

Datei anzeigen

@ -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

Datei anzeigen

@ -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

Datei anzeigen

@ -1,5 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
class CustomWizard::ProAuthenticationSerializer < ApplicationSerializer class CustomWizard::Subscription::AuthenticationSerializer < ApplicationSerializer
attributes :active, attributes :active,
:client_id, :client_id,
:auth_by, :auth_by,

Datei anzeigen

@ -1,5 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
class CustomWizard::ProSubscriptionSerializer < ApplicationSerializer class CustomWizard::Subscription::SubscriptionSerializer < ApplicationSerializer
attributes :type, attributes :type,
:active, :active,
:updated_at :updated_at

Datei anzeigen

@ -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

Datei anzeigen

@ -123,6 +123,6 @@ class CustomWizard::FieldSerializer < ::ApplicationSerializer
end end
def subscribed? def subscribed?
@subscribed ||= CustomWizard::Pro.subscribed? @subscribed ||= CustomWizard::Subscription.subscribed?
end end
end end

Datei anzeigen

@ -10,7 +10,7 @@ class CustomWizard::WizardSerializer < CustomWizard::BasicWizardSerializer
:permitted, :permitted,
:uncategorized_category_id, :uncategorized_category_id,
:categories, :categories,
:pro_subscribed :subscribed
has_many :steps, serializer: ::CustomWizard::StepSerializer, embed: :objects has_many :steps, serializer: ::CustomWizard::StepSerializer, embed: :objects
has_one :user, serializer: ::BasicUserSerializer, 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 } object.categories.map { |c| c.to_h }
end end
def pro_subscribed def subscribed
CustomWizard::Pro.subscribed? CustomWizard::Subscription.subscribed?
end end
end end

Datei anzeigen

@ -80,8 +80,4 @@ class CustomWizard::StepSerializer < ::ApplicationSerializer
def i18n_key def i18n_key
@i18n_key ||= "#{object.wizard.id}.#{object.id}".underscore @i18n_key ||= "#{object.wizard.id}.#{object.id}".underscore
end end
def subscribed?
@subscribed ||= CustomWizard::Pro.subscribed?
end
end end

Datei anzeigen

@ -174,7 +174,7 @@ describe CustomWizard::Action do
expect(updater.result[:redirect_on_next]).to eq("https://google.com") expect(updater.result[:redirect_on_next]).to eq("https://google.com")
end end
context "pro actions" do context "subscription actions" do
before do before do
enable_subscription enable_subscription
end end

Datei anzeigen

@ -4,7 +4,7 @@ require_relative '../../plugin_helper'
describe CustomWizard::CustomField do describe CustomWizard::CustomField do
let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") } 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 before do
CustomWizard::CustomField.invalidate_cache CustomWizard::CustomField.invalidate_cache
@ -193,44 +193,44 @@ describe CustomWizard::CustomField do
).to eq(false) ).to eq(false)
end end
it "does not save pro field types without a pro subscription" do it "does not save subscription field types without a subscription" do
pro_field_json = custom_field_pro_json['custom_fields'].first subscription_field_json = custom_field_subscription_json['custom_fields'].first
custom_field = CustomWizard::CustomField.new(nil, pro_field_json) custom_field = CustomWizard::CustomField.new(nil, subscription_field_json)
expect(custom_field.save).to eq(false) expect(custom_field.save).to eq(false)
expect(custom_field.valid?).to eq(false) expect(custom_field.valid?).to eq(false)
expect(custom_field.errors.full_messages.first).to eq( 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 end
it "does not save pro field classes without a pro subscription" do it "does not save subscription field classes without a subscription" do
pro_field_json = custom_field_pro_json['custom_fields'].second subscription_field_json = custom_field_subscription_json['custom_fields'].second
custom_field = CustomWizard::CustomField.new(nil, pro_field_json) custom_field = CustomWizard::CustomField.new(nil, subscription_field_json)
expect(custom_field.save).to eq(false) expect(custom_field.save).to eq(false)
expect(custom_field.valid?).to eq(false) expect(custom_field.valid?).to eq(false)
expect(custom_field.errors.full_messages.first).to eq( 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 end
context "with a pro subscription" do context "with a subscription" do
before do before do
enable_subscription enable_subscription
end end
it "saves pro field types" do it "saves subscription field types" do
pro_field_json = custom_field_pro_json['custom_fields'].first subscription_field_json = custom_field_subscription_json['custom_fields'].first
custom_field = CustomWizard::CustomField.new(nil, pro_field_json) custom_field = CustomWizard::CustomField.new(nil, subscription_field_json)
expect(custom_field.save).to eq(true) expect(custom_field.save).to eq(true)
expect(custom_field.valid?).to eq(true) expect(custom_field.valid?).to eq(true)
end end
it "saves pro field classes" do it "saves subscription field classes" do
pro_field_json = custom_field_pro_json['custom_fields'].second subscription_field_json = custom_field_subscription_json['custom_fields'].second
custom_field = CustomWizard::CustomField.new(nil, pro_field_json) custom_field = CustomWizard::CustomField.new(nil, subscription_field_json)
expect(custom_field.save).to eq(true) expect(custom_field.save).to eq(true)
expect(custom_field.valid?).to eq(true) expect(custom_field.valid?).to eq(true)

Datei anzeigen

@ -344,7 +344,7 @@ describe CustomWizard::Mapper do
expect(result).to eq(template_params["step_1_field_1"]) expect(result).to eq(template_params["step_1_field_1"])
end end
it "requires a pro subscription" do it "requires a subscription" do
template = '{{ "w{step_1_field_1}" | size }}' template = '{{ "w{step_1_field_1}" | size }}'
mapper = create_template_mapper(template_params, user1) mapper = create_template_mapper(template_params, user1)
result = mapper.interpolate( result = mapper.interpolate(
@ -357,7 +357,7 @@ describe CustomWizard::Mapper do
expect(result).to eq("{{ \"#{template_params["step_1_field_1"]}\" | size }}") expect(result).to eq("{{ \"#{template_params["step_1_field_1"]}\" | size }}")
end end
context "with a pro subscription" do context "with a subscription" do
before do before do
enable_subscription enable_subscription
end end

Datei anzeigen

@ -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

Datei anzeigen

@ -2,69 +2,69 @@
require_relative '../../plugin_helper' require_relative '../../plugin_helper'
describe CustomWizard::Pro do describe CustomWizard::Subscription do
fab!(:user) { Fabricate(:user) } fab!(:user) { Fabricate(:user) }
it "initializes pro authentication and subscription" do it "initializes subscription authentication and subscription" do
pro = described_class.new subscription = described_class.new
expect(pro.authentication.class).to eq(CustomWizard::ProAuthentication) expect(subscription.authentication.class).to eq(CustomWizard::Subscription::Authentication)
expect(pro.subscription.class).to eq(CustomWizard::ProSubscription) expect(subscription.subscription.class).to eq(CustomWizard::Subscription::Subscription)
end end
it "returns authorized and subscribed states" do it "returns authorized and subscribed states" do
pro = described_class.new subscription = described_class.new
expect(pro.authorized?).to eq(false) expect(subscription.authorized?).to eq(false)
expect(pro.subscribed?).to eq(false) expect(subscription.subscribed?).to eq(false)
end end
context "subscription" do context "subscription" do
before do before do
@pro = described_class.new @subscription = described_class.new
end end
it "updates valid subscriptions" do it "updates valid subscriptions" do
stub_subscription_request(200, valid_subscription) stub_subscription_request(200, valid_subscription)
expect(@pro.update_subscription).to eq(true) expect(@subscription.update).to eq(true)
expect(@pro.subscribed?).to eq(true) expect(@subscription.subscribed?).to eq(true)
end end
it "handles invalid subscriptions" do it "handles invalid subscriptions" do
stub_subscription_request(200, invalid_subscription) stub_subscription_request(200, invalid_subscription)
expect(@pro.update_subscription).to eq(false) expect(@subscription.update).to eq(false)
expect(@pro.subscribed?).to eq(false) expect(@subscription.subscribed?).to eq(false)
end end
it "handles subscription http errors" do it "handles subscription http errors" do
stub_subscription_request(404, {}) stub_subscription_request(404, {})
expect(@pro.update_subscription).to eq(false) expect(@subscription.update).to eq(false)
expect(@pro.subscribed?).to eq(false) expect(@subscription.subscribed?).to eq(false)
end end
it "destroys subscriptions" do it "destroys subscriptions" do
stub_subscription_request(200, valid_subscription) stub_subscription_request(200, valid_subscription)
expect(@pro.update_subscription).to eq(true) expect(@subscription.update).to eq(true)
expect(@pro.destroy_subscription).to eq(true) expect(@subscription.destroy_subscription).to eq(true)
expect(@pro.subscribed?).to eq(false) expect(@subscription.subscribed?).to eq(false)
end end
it "has class aliases" do it "has class aliases" do
authenticate_pro authenticate_subscription
stub_subscription_request(200, valid_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) expect(described_class.subscribed?).to eq(true)
end end
end end
context "authentication" do context "authentication" do
before do before do
@pro = described_class.new @subscription = described_class.new
user.update!(admin: true) user.update!(admin: true)
end end
it "generates a valid authentication request url" do it "generates a valid authentication request url" do
request_id = SecureRandom.hex(32) request_id = SecureRandom.hex(32)
uri = URI(@pro.authentication_url(user.id, request_id)) uri = URI(@subscription.authentication_url(user.id, request_id))
expect(uri.host).to eq(@pro.server) expect(uri.host).to eq(@subscription.server)
parsed_query = Rack::Utils.parse_query uri.query parsed_query = Rack::Utils.parse_query uri.query
expect(parsed_query['public_key'].present?).to eq(true) 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['client_id'].present?).to eq(true)
expect(parsed_query['auth_redirect'].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['application_name']).to eq(SiteSetting.title)
expect(parsed_query['scopes']).to eq(@pro.scope) expect(parsed_query['scopes']).to eq(@subscription.scope)
end end
def generate_payload(request_id, user_id) def generate_payload(request_id, user_id)
uri = URI(@pro.authentication_url(user_id, request_id)) uri = URI(@subscription.authentication_url(user_id, request_id))
keys = @pro.authentication.get_keys(request_id) keys = @subscription.authentication.get_keys(request_id)
raw_payload = { raw_payload = {
key: "12345", key: "12345",
nonce: keys.nonce, nonce: keys.nonce,
@ -92,8 +92,8 @@ describe CustomWizard::Pro do
request_id = SecureRandom.hex(32) request_id = SecureRandom.hex(32)
payload = generate_payload(request_id, user.id) payload = generate_payload(request_id, user.id)
expect(@pro.authentication_response(request_id, payload)).to eq(true) expect(@subscription.authentication_response(request_id, payload)).to eq(true)
expect(@pro.authorized?).to eq(true) expect(@subscription.authorized?).to eq(true)
end end
it "discards authentication response if user who made request as not an admin" do 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) request_id = SecureRandom.hex(32)
payload = generate_payload(request_id, user.id) payload = generate_payload(request_id, user.id)
expect(@pro.authentication_response(request_id, payload)).to eq(false) expect(@subscription.authentication_response(request_id, payload)).to eq(false)
expect(@pro.authorized?).to eq(false) expect(@subscription.authorized?).to eq(false)
end end
it "discards authentication response if request_id is invalid" do it "discards authentication response if request_id is invalid" do
payload = generate_payload(SecureRandom.hex(32), user.id) payload = generate_payload(SecureRandom.hex(32), user.id)
expect(@pro.authentication_response(SecureRandom.hex(32), payload)).to eq(false) expect(@subscription.authentication_response(SecureRandom.hex(32), payload)).to eq(false)
expect(@pro.authorized?).to eq(false) expect(@subscription.authorized?).to eq(false)
end end
it "destroys authentication" do it "destroys authentication" do
request_id = SecureRandom.hex(32) request_id = SecureRandom.hex(32)
payload = generate_payload(request_id, user.id) 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(@subscription.destroy_authentication).to eq(true)
expect(@pro.authorized?).to eq(false) expect(@subscription.authorized?).to eq(false)
end end
end end
end end

Datei anzeigen

@ -10,7 +10,7 @@ describe "custom field extensions" do
fab!(:user) { Fabricate(:user) } fab!(:user) { Fabricate(:user) }
let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") } 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 before do
custom_field_json['custom_fields'].each do |field_json| custom_field_json['custom_fields'].each do |field_json|
@ -72,11 +72,11 @@ describe "custom field extensions" do
end end
end end
context "pro custom fields" do context "subscription custom fields" do
before do before do
enable_subscription 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 = CustomWizard::CustomField.new(nil, field_json)
custom_field.save custom_field.save
end end

Datei anzeigen

@ -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

Datei anzeigen

@ -2,10 +2,10 @@
require_relative '../plugin_helper' require_relative '../plugin_helper'
describe CustomWizard::UpdateProSubscription do describe Jobs::CustomWizardUpdateSubscription do
it "updates the pro subscription" do it "updates the subscription" do
stub_subscription_request(200, valid_subscription) stub_subscription_request(200, valid_subscription)
described_class.new.execute described_class.new.execute
expect(CustomWizard::Pro.subscribed?).to eq(true) expect(CustomWizard::Subscription.subscribed?).to eq(true)
end end
end end

Datei anzeigen

@ -24,16 +24,16 @@ def get_wizard_fixture(path)
).with_indifferent_access ).with_indifferent_access
end end
def authenticate_pro def authenticate_subscription
CustomWizard::ProAuthentication.any_instance.stubs(:active?).returns(true) CustomWizard::Subscription::Authentication.any_instance.stubs(:active?).returns(true)
end end
def enable_subscription def enable_subscription
CustomWizard::Pro.any_instance.stubs(:subscribed?).returns(true) CustomWizard::Subscription.any_instance.stubs(:subscribed?).returns(true)
end end
def disable_pro def disable_subscription
CustomWizard::Pro.any_instance.stubs(:subscribed?).returns(false) CustomWizard::Subscription.any_instance.stubs(:subscribed?).returns(false)
end end
def valid_subscription def valid_subscription
@ -52,7 +52,7 @@ def invalid_subscription
end end
def stub_subscription_request(status, subscription) def stub_subscription_request(status, subscription)
authenticate_pro authenticate_subscription
pro = CustomWizard::Pro.new sub = CustomWizard::Subscription.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) 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 end

Datei anzeigen

@ -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

Datei anzeigen

@ -1,12 +1,12 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative '../../../plugin_helper' require_relative '../../../plugin_helper'
describe CustomWizard::AdminProController do describe CustomWizard::AdminSubscriptionController do
fab!(:admin_user) { Fabricate(:user, admin: true) } fab!(:admin_user) { Fabricate(:user, admin: true) }
def generate_payload(request_id, user_id) def generate_payload(request_id, user_id)
uri = URI(@pro.authentication_url(user_id, request_id)) uri = URI(@subscription.authentication_url(user_id, request_id))
keys = @pro.authentication.get_keys(request_id) keys = @subscription.authentication.get_keys(request_id)
raw_payload = { raw_payload = {
key: "12345", key: "12345",
nonce: keys.nonce, nonce: keys.nonce,
@ -18,19 +18,19 @@ describe CustomWizard::AdminProController do
end end
before do before do
@pro = CustomWizard::Pro.new @subscription = CustomWizard::Subscription.new
sign_in(admin_user) sign_in(admin_user)
end end
it "#index" do it "#index" do
get "/admin/wizards/pro.json" get "/admin/wizards/subscription.json"
expect(response.parsed_body['server']).to eq(@pro.server) expect(response.parsed_body['server']).to eq(@subscription.server)
expect(response.parsed_body['authentication'].deep_symbolize_keys).to eq(CustomWizard::ProAuthenticationSerializer.new(@pro.authentication, root: false).as_json) 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::ProSubscriptionSerializer.new(@pro.subscription, 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 end
it "#authorize" do it "#authorize" do
get "/admin/wizards/pro/authorize" get "/admin/wizards/subscription/authorize"
expect(response.status).to eq(302) expect(response.status).to eq(302)
expect(cookies[:user_api_request_id].present?).to eq(true) expect(cookies[:user_api_request_id].present?).to eq(true)
end end
@ -38,12 +38,12 @@ describe CustomWizard::AdminProController do
it "#destroy_authentication" do it "#destroy_authentication" do
request_id = SecureRandom.hex(32) request_id = SecureRandom.hex(32)
payload = generate_payload(request_id, admin_user.id) 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(response.status).to eq(200)
expect(CustomWizard::Pro.authorized?).to eq(false) expect(CustomWizard::Subscription.authorized?).to eq(false)
end end
context "subscription" do context "subscription" do
@ -54,18 +54,18 @@ describe CustomWizard::AdminProController do
it "handles authentication response and the updates subscription" do it "handles authentication response and the updates subscription" do
request_id = cookies[:user_api_request_id] = SecureRandom.hex(32) request_id = cookies[:user_api_request_id] = SecureRandom.hex(32)
payload = generate_payload(request_id, admin_user.id) 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(response).to redirect_to("/admin/wizards/subscription")
expect(CustomWizard::Pro.subscribed?).to eq(true) expect(CustomWizard::Subscription.subscribed?).to eq(true)
end end
it "updates the subscription" do it "updates the subscription" do
authenticate_pro authenticate_subscription
post "/admin/wizards/pro/subscription.json" post "/admin/wizards/subscription.json"
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(CustomWizard::Pro.subscribed?).to eq(true) expect(CustomWizard::Subscription.subscribed?).to eq(true)
end end
end end
end end

Datei anzeigen

@ -9,7 +9,7 @@ describe "custom field extensions" do
let!(:user) { Fabricate(:user) } let!(:user) { Fabricate(:user) }
let!(:group) { Fabricate(:group, users: [user]) } let!(:group) { Fabricate(:group, users: [user]) }
let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") } 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 before do
custom_field_json['custom_fields'].each do |field_json| 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) expect(response.parsed_body['post_field_1']).to eq(7)
end end
context "with a pro subscription" do context "with a subscription" do
before do before do
enable_subscription 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 = CustomWizard::CustomField.new(nil, field_json)
custom_field.save custom_field.save
end end

Datei anzeigen

@ -119,7 +119,7 @@ describe CustomWizard::StepsController do
expect(response.parsed_body['final']).to eq(true) expect(response.parsed_body['final']).to eq(true)
end end
context "pro" do context "subscription" do
before do before do
enable_subscription enable_subscription
end end
@ -149,6 +149,38 @@ describe CustomWizard::StepsController do
expect(response.parsed_body['wizard']['start']).to eq("step_3") expect(response.parsed_body['wizard']['start']).to eq("step_3")
end 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 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 = wizard_template.dup
new_template['steps'][0]['condition'] = user_condition_template['condition'] new_template['steps'][0]['condition'] = user_condition_template['condition']

Datei anzeigen

@ -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

Datei anzeigen

@ -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

Datei anzeigen

@ -2,11 +2,11 @@
require_relative '../../../plugin_helper' require_relative '../../../plugin_helper'
describe CustomWizard::ProAuthenticationSerializer do describe CustomWizard::Subscription::AuthenticationSerializer do
fab!(:user) { Fabricate(:user) } fab!(:user) { Fabricate(:user) }
it 'should return pro authentication attributes' do it 'should return subscription authentication attributes' do
auth = CustomWizard::ProAuthentication.new(OpenStruct.new(key: '1234', auth_at: Time.now, auth_by: user.id)) 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 serialized = described_class.new(auth, root: false).as_json
expect(serialized[:active]).to eq(true) expect(serialized[:active]).to eq(true)

Datei anzeigen

@ -2,9 +2,9 @@
require_relative '../../../plugin_helper' require_relative '../../../plugin_helper'
describe CustomWizard::ProSubscriptionSerializer do describe CustomWizard::Subscription::SubscriptionSerializer do
it 'should return pro subscription attributes' do it 'should return subscription attributes' do
sub = CustomWizard::ProSubscription.new(OpenStruct.new(type: 'community', updated_at: Time.now)) sub = CustomWizard::Subscription::Subscription.new(OpenStruct.new(type: 'community', updated_at: Time.now))
serialized = described_class.new(sub, root: false).as_json serialized = described_class.new(sub, root: false).as_json
expect(serialized[:active]).to eq(true) expect(serialized[:active]).to eq(true)

Datei anzeigen

@ -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