wip
Dieser Commit ist enthalten in:
Ursprung
270d3bccf5
Commit
084c6f4a7a
94 geänderte Dateien mit 1228 neuen und 413 gelöschten Zeilen
|
@ -6,20 +6,20 @@ import I18n from "I18n";
|
|||
|
||||
const klasses = ["topic", "post", "group", "category"];
|
||||
const types = ["string", "boolean", "integer", "json"];
|
||||
const proTypes = {
|
||||
const subscriptionTypes = {
|
||||
klass: ["group", "category"],
|
||||
type: ["json"],
|
||||
};
|
||||
|
||||
const generateContent = function (array, type, proSubscribed = false) {
|
||||
const generateContent = function (array, type, subscribed = false) {
|
||||
return array.reduce((result, key) => {
|
||||
let proArr = proTypes[type];
|
||||
let pro = proArr && proArr.includes(key);
|
||||
if (!pro || proSubscribed) {
|
||||
let subArr = subscriptionTypes[type];
|
||||
let subscription = subArr && subArr.includes(key);
|
||||
if (!subscription || subscribed) {
|
||||
result.push({
|
||||
id: key,
|
||||
name: I18n.t(`admin.wizard.custom_field.${type}.${key}`),
|
||||
pro,
|
||||
subscription,
|
||||
});
|
||||
}
|
||||
return result;
|
||||
|
@ -32,11 +32,11 @@ export default Component.extend({
|
|||
postSerializers: ["post"],
|
||||
groupSerializers: ["basic_group"],
|
||||
categorySerializers: ["basic_category"],
|
||||
klassContent: computed("proSubscribed", function () {
|
||||
return generateContent(klasses, "klass", this.proSubscribed);
|
||||
klassContent: computed("subscribed", function () {
|
||||
return generateContent(klasses, "klass", this.subscribed);
|
||||
}),
|
||||
typeContent: computed("proSubscribed", function () {
|
||||
return generateContent(types, "type", this.proSubscribed);
|
||||
typeContent: computed("subscribed", function () {
|
||||
return generateContent(types, "type", this.subscribed);
|
||||
}),
|
||||
showInputs: or("field.new", "field.edit"),
|
||||
classNames: ["custom-field-input"],
|
||||
|
@ -54,7 +54,7 @@ export default Component.extend({
|
|||
const serializers = this.get(`${klass}Serializers`);
|
||||
|
||||
if (serializers) {
|
||||
return generateContent(serializers, "serializers", this.proSubscribed);
|
||||
return generateContent(serializers, "serializers", this.subscribed);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
|
|
@ -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`;
|
||||
}
|
||||
})
|
|
@ -94,15 +94,15 @@ export default Component.extend(UndoChanges, {
|
|||
return apis.find((a) => a.name === api).endpoints;
|
||||
},
|
||||
|
||||
@discourseComputed("proSubscribed")
|
||||
actionTypes(proSubscribed) {
|
||||
@discourseComputed("subscribed")
|
||||
actionTypes(subscribed) {
|
||||
return Object.keys(wizardSchema.action.types).reduce((result, type) => {
|
||||
let pro = wizardSchema.action.proTypes.includes(type);
|
||||
if (proSubscribed || !pro) {
|
||||
let subscription = wizardSchema.action.subscriptionTypes.includes(type);
|
||||
if (subscribed || !subscription) {
|
||||
result.push({
|
||||
id: type,
|
||||
name: I18n.t(`admin.wizard.action.${type}.label`),
|
||||
pro,
|
||||
subscription,
|
||||
});
|
||||
}
|
||||
return result;
|
||||
|
|
34
assets/javascripts/discourse/components/wizard-notice.js.es6
Normale Datei
34
assets/javascripts/discourse/components/wizard-notice.js.es6
Normale Datei
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
|
@ -6,7 +6,7 @@ import discourseComputed from "discourse-common/utils/decorators";
|
|||
import I18n from "I18n";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["realtime-validations", "setting", "full", "pro"],
|
||||
classNames: ["realtime-validations", "setting", "full", "subscription"],
|
||||
|
||||
@discourseComputed
|
||||
timeUnits() {
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import SingleSelectComponent from "select-kit/components/single-select";
|
||||
|
||||
export default SingleSelectComponent.extend({
|
||||
classNames: ["combo-box", "wizard-pro-selector"],
|
||||
classNames: ["combo-box", "wizard-subscription-selector"],
|
||||
|
||||
selectKitOptions: {
|
||||
autoFilterable: false,
|
||||
filterable: false,
|
||||
showFullTitle: true,
|
||||
headerComponent: "wizard-pro-selector/wizard-pro-selector-header",
|
||||
headerComponent: "wizard-subscription-selector/wizard-subscription-selector-header",
|
||||
caretUpIcon: "caret-up",
|
||||
caretDownIcon: "caret-down",
|
||||
},
|
||||
|
||||
modifyComponentForRow() {
|
||||
return "wizard-pro-selector/wizard-pro-selector-row";
|
||||
return "wizard-subscription-selector/wizard-subscription-selector-row";
|
||||
},
|
||||
});
|
|
@ -3,7 +3,7 @@ import { computed } from "@ember/object";
|
|||
import { reads } from "@ember/object/computed";
|
||||
|
||||
export default SingleSelectHeaderComponent.extend({
|
||||
classNames: ["combo-box-header", "wizard-pro-selector-header"],
|
||||
classNames: ["combo-box-header", "wizard-subscription-selector-header"],
|
||||
caretUpIcon: reads("selectKit.options.caretUpIcon"),
|
||||
caretDownIcon: reads("selectKit.options.caretDownIcon"),
|
||||
caretIcon: computed(
|
|
@ -1,12 +1,12 @@
|
|||
import Component from "@ember/component";
|
||||
import CustomWizardPro from "../models/custom-wizard-pro";
|
||||
import CustomWizardSubscription from "../models/custom-wizard-subscription";
|
||||
import { notEmpty } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: [
|
||||
":custom-wizard-pro-subscription",
|
||||
":custom-wizard-subscription",
|
||||
"subscription.active:active:inactive",
|
||||
],
|
||||
subscribed: notEmpty("subscription"),
|
||||
|
@ -14,8 +14,8 @@ export default Component.extend({
|
|||
@discourseComputed("subscription.type")
|
||||
title(type) {
|
||||
return type
|
||||
? I18n.t(`admin.wizard.pro.subscription.title.${type}`)
|
||||
: I18n.t("admin.wizard.pro.not_subscribed");
|
||||
? I18n.t(`admin.wizard.subscription.subscription.title.${type}`)
|
||||
: I18n.t("admin.wizard.subscription.not_subscribed");
|
||||
},
|
||||
|
||||
@discourseComputed("subscription.active")
|
||||
|
@ -25,13 +25,13 @@ export default Component.extend({
|
|||
|
||||
@discourseComputed("stateClass")
|
||||
stateLabel(stateClass) {
|
||||
return I18n.t(`admin.wizard.pro.subscription.status.${stateClass}`);
|
||||
return I18n.t(`admin.wizard.subscription.subscription.status.${stateClass}`);
|
||||
},
|
||||
|
||||
actions: {
|
||||
update() {
|
||||
this.set("updating", true);
|
||||
CustomWizardPro.update_subscription()
|
||||
CustomWizardSubscription.update()
|
||||
.then((result) => {
|
||||
if (result.success) {
|
||||
this.setProperties({
|
|
@ -0,0 +1,3 @@
|
|||
{{#if wizardWarningNotice}}
|
||||
{{wizard-notice notice=wizardWarningNotice}}
|
||||
{{/if}}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
{{#if currentUser.admin}}
|
||||
{{nav-item route="adminWizards" label="admin.wizard.nav_label"}}
|
||||
|
||||
{{#if wizardErrorNotice}}
|
||||
{{d-icon "exclaimation-circle"}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Controller from "@ember/controller";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import CustomWizardPro from "../models/custom-wizard-pro";
|
||||
import CustomWizardSubscription from "../models/custom-wizard-subscription";
|
||||
import { alias } from "@ember/object/computed";
|
||||
|
||||
export default Controller.extend({
|
20
assets/javascripts/discourse/controllers/admin-wizards.js.es6
Normale Datei
20
assets/javascripts/discourse/controllers/admin-wizards.js.es6
Normale Datei
|
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
|
@ -59,8 +59,8 @@ export default {
|
|||
resetNamespace: true,
|
||||
});
|
||||
|
||||
this.route("adminWizardsPro", {
|
||||
path: "/pro",
|
||||
this.route("adminWizardsSubscription", {
|
||||
path: "/subscription",
|
||||
resetNamespace: true,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import DiscourseURL from "discourse/lib/url";
|
||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import CustomWizardNotice from "../models/custom-wizard-notice";
|
||||
import { A } from "@ember/array";
|
||||
|
||||
export default {
|
||||
name: "custom-wizard-edits",
|
||||
|
@ -16,5 +20,29 @@ export default {
|
|||
}
|
||||
return existing.apply(this, [path, opts]);
|
||||
};
|
||||
|
||||
withPluginApi("0.8.36", (api) => {
|
||||
api.modifyClass('route:admin-dashboard', {
|
||||
afterModel() {
|
||||
return CustomWizardNotice.list().then(result => {
|
||||
if (result && result.length) {
|
||||
this.set('notices', A(result.map(n => CustomWizardNotice.create(n))));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
if (this.notices) {
|
||||
let warningNotices = this.notices.filter(n => n.type === 'warning');
|
||||
|
||||
if (warningNotices.length) {
|
||||
controller.set('wizardWarningNotice', warningNotices[0]);
|
||||
}
|
||||
}
|
||||
|
||||
this._super(...arguments);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -193,6 +193,14 @@ const action = {
|
|||
"members_visibility_level",
|
||||
],
|
||||
required: ["id", "type"],
|
||||
subscriptionTypes: [
|
||||
"send_message",
|
||||
"add_to_group",
|
||||
"create_category",
|
||||
"create_group",
|
||||
"send_to_api",
|
||||
],
|
||||
required: ["id", "type"],
|
||||
proTypes: [
|
||||
"send_message",
|
||||
"add_to_group",
|
||||
|
|
23
assets/javascripts/discourse/models/custom-wizard-notice.js.es6
Normale Datei
23
assets/javascripts/discourse/models/custom-wizard-notice.js.es6
Normale Datei
|
@ -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;
|
|
@ -2,11 +2,11 @@ import { ajax } from "discourse/lib/ajax";
|
|||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import EmberObject from "@ember/object";
|
||||
|
||||
const CustomWizardPro = EmberObject.extend();
|
||||
const CustomWizardSubscription = EmberObject.extend();
|
||||
|
||||
const basePath = "/admin/wizards/pro";
|
||||
const basePath = "/admin/wizards/subscription";
|
||||
|
||||
CustomWizardPro.reopenClass({
|
||||
CustomWizardSubscription.reopenClass({
|
||||
status() {
|
||||
return ajax(basePath, {
|
||||
type: "GET",
|
||||
|
@ -23,11 +23,11 @@ CustomWizardPro.reopenClass({
|
|||
}).catch(popupAjaxError);
|
||||
},
|
||||
|
||||
update_subscription() {
|
||||
return ajax(`${basePath}/subscription`, {
|
||||
update() {
|
||||
return ajax(basePath, {
|
||||
type: "POST",
|
||||
}).catch(popupAjaxError);
|
||||
},
|
||||
});
|
||||
|
||||
export default CustomWizardPro;
|
||||
export default CustomWizardSubscription;
|
|
@ -9,11 +9,11 @@ export default DiscourseRoute.extend({
|
|||
|
||||
setupController(controller, model) {
|
||||
const customFields = A(model.custom_fields || []);
|
||||
const proSubscribed = model.pro_subscribed;
|
||||
const subscribed = model.subscribed;
|
||||
|
||||
controller.setProperties({
|
||||
customFields,
|
||||
proSubscribed,
|
||||
subscribed,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import CustomWizardPro from "../models/custom-wizard-pro";
|
||||
import CustomWizardSubscription from "../models/custom-wizard-subscription";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
model() {
|
||||
return CustomWizardPro.status();
|
||||
return CustomWizardSubscription.status();
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
|
@ -13,7 +13,7 @@ export default DiscourseRoute.extend({
|
|||
|
||||
actions: {
|
||||
authorize() {
|
||||
CustomWizardPro.authorize();
|
||||
CustomWizardSubscription.authorize();
|
||||
},
|
||||
},
|
||||
});
|
|
@ -39,7 +39,7 @@ export default DiscourseRoute.extend({
|
|||
currentStep: wizard.steps[0],
|
||||
currentAction: wizard.actions[0],
|
||||
creating: model.create,
|
||||
proSubscribed: parentModel.pro_subscribed,
|
||||
subscribed: parentModel.subscribed,
|
||||
};
|
||||
|
||||
controller.setProperties(props);
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { A } from "@ember/array";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
beforeModel(transition) {
|
||||
model() {
|
||||
return ajax('/admin/wizards');
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
controller.set('notices', A(model.notices));
|
||||
},
|
||||
|
||||
afterModel(model, transition) {
|
||||
if (transition.targetName === "adminWizards.index") {
|
||||
this.transitionTo("adminWizardsWizard");
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
field=field
|
||||
removeField=(action "removeField")
|
||||
saveField=(action "saveField")
|
||||
proSubscribed=proSubscribed}}
|
||||
subscribed=subscribed}}
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -126,11 +126,10 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{{#if proSubscribed}}
|
||||
<div class="setting pro">
|
||||
{{#subscription-container subscribed=subscribed}}
|
||||
<div class="setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.save_submissions"}}</label>
|
||||
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||
</div>
|
||||
<div class="setting-value">
|
||||
{{input type="checkbox" checked=wizard.save_submissions}}
|
||||
|
@ -138,17 +137,16 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting pro">
|
||||
<div class="setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.restart_on_revisit"}}</label>
|
||||
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||
</div>
|
||||
<div class="setting-value">
|
||||
{{input type="checkbox" checked=wizard.restart_on_revisit}}
|
||||
<span>{{i18n "admin.wizard.restart_on_revisit_label"}}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/subscription-container}}
|
||||
</div>
|
||||
|
||||
{{wizard-links
|
||||
|
@ -163,7 +161,7 @@
|
|||
currentField=currentField
|
||||
wizardFields=wizardFields
|
||||
fieldTypes=fieldTypes
|
||||
proSubscribed=proSubscribed}}
|
||||
subscribed=subscribed}}
|
||||
{{/if}}
|
||||
|
||||
{{wizard-links
|
||||
|
@ -180,7 +178,7 @@
|
|||
apis=apis
|
||||
removeAction="removeAction"
|
||||
wizardFields=wizardFields
|
||||
proSubscribed=proSubscribed}}
|
||||
subscribed=subscribed}}
|
||||
{{/each}}
|
||||
|
||||
<div class="admin-wizard-buttons">
|
||||
|
|
|
@ -7,13 +7,18 @@
|
|||
{{/if}}
|
||||
{{nav-item route="adminWizardsLogs" label="admin.wizard.log.nav_label"}}
|
||||
{{nav-item route="adminWizardsManager" label="admin.wizard.manager.nav_label"}}
|
||||
{{nav-item route="adminWizardsPro" label="admin.wizard.pro.nav_label"}}
|
||||
{{nav-item route="adminWizardsSubscription" label="admin.wizard.subscription.nav_label"}}
|
||||
|
||||
<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>
|
||||
{{/admin-nav}}
|
||||
|
||||
<div class="admin-container">
|
||||
{{#each notices as |notice|}}
|
||||
{{wizard-notice notice=notice}}
|
||||
{{/each}}
|
||||
{{outlet}}
|
||||
</div>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
{{#if showInputs}}
|
||||
<td>
|
||||
{{wizard-pro-selector
|
||||
{{wizard-subscription-selector
|
||||
value=field.klass
|
||||
content=klassContent
|
||||
none="admin.wizard.custom_field.klass.select"
|
||||
onChange=(action (mut field.klass))}}
|
||||
</td>
|
||||
<td>
|
||||
{{wizard-pro-selector
|
||||
{{wizard-subscription-selector
|
||||
value=field.type
|
||||
content=typeContent
|
||||
none="admin.wizard.custom_field.type.select"
|
||||
|
|
|
@ -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>
|
|
@ -12,7 +12,7 @@
|
|||
</div>
|
||||
|
||||
<div class="setting-value">
|
||||
{{wizard-pro-selector
|
||||
{{wizard-subscription-selector
|
||||
value=action.type
|
||||
content=actionTypes
|
||||
onChange=(action "changeType")
|
||||
|
|
|
@ -207,11 +207,10 @@
|
|||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if proSubscribed}}
|
||||
<div class="setting full field-mapper-setting pro">
|
||||
{{#subscription-container subscribed=subscribed}}
|
||||
<div class="setting full field-mapper-setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.condition"}}</label>
|
||||
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||
</div>
|
||||
|
||||
<div class="setting-value">
|
||||
|
@ -221,10 +220,9 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting full field-mapper-setting pro">
|
||||
<div class="setting full field-mapper-setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.index"}}</label>
|
||||
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||
<label>{{i18n "admin.wizard.index"}}</label>>
|
||||
</div>
|
||||
|
||||
<div class="setting-value">
|
||||
|
@ -256,4 +254,4 @@
|
|||
{{#if validations}}
|
||||
{{wizard-realtime-validations field=field validations=validations}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/subscription-container}}
|
||||
|
|
|
@ -33,11 +33,10 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{{#if proSubscribed}}
|
||||
<div class="setting full field-mapper-setting pro">
|
||||
{{#subscription-container subscribed=subscribed}}
|
||||
<div class="setting full field-mapper-setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.condition"}}</label>
|
||||
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||
</div>
|
||||
|
||||
<div class="setting-value">
|
||||
|
@ -83,10 +82,9 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting full field-mapper-setting pro">
|
||||
<div class="setting full field-mapper-setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.step.permitted_params.label"}}</label>
|
||||
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||
</div>
|
||||
<div class="setting-value">
|
||||
{{wizard-mapper
|
||||
|
@ -100,7 +98,7 @@
|
|||
)}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/subscription-container}}
|
||||
|
||||
{{wizard-links
|
||||
itemType="field"
|
||||
|
@ -116,5 +114,5 @@
|
|||
fieldTypes=fieldTypes
|
||||
removeField="removeField"
|
||||
wizardFields=wizardFields
|
||||
proSubscribed=proSubscribed}}
|
||||
subscribed=subscribed}}
|
||||
{{/each}}
|
||||
|
|
37
assets/javascripts/discourse/templates/components/wizard-notice.hbs
Normale Datei
37
assets/javascripts/discourse/templates/components/wizard-notice.hbs
Normale Datei
|
@ -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}}
|
|
@ -1,6 +1,5 @@
|
|||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.field.validations.header"}}</label>
|
||||
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||
</div>
|
||||
<div class="setting-value full">
|
||||
<ul>
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
shouldDisplayClearableButton=shouldDisplayClearableButton
|
||||
}}
|
||||
|
||||
{{#if selectedContent.pro}}
|
||||
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||
{{#if selectedContent.subscription}}
|
||||
<span class="subscription-label">{{i18n "admin.wizard.subscription.label"}}</span>
|
||||
{{/if}}
|
||||
|
||||
{{d-icon caretIcon class="caret-icon"}}
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
<div class="texts">
|
||||
<span class="name">{{html-safe label}}</span>
|
||||
{{#if item.pro}}
|
||||
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||
{{#if item.subscription}}
|
||||
<span class="subscription-label">{{i18n "admin.wizard.subscription.label"}}</span>
|
||||
{{/if}}
|
||||
</div>
|
|
@ -13,8 +13,8 @@
|
|||
icon="sync"
|
||||
action=(action "update")
|
||||
disabled=updating
|
||||
title="admin.wizard.pro.subscription.update"
|
||||
label="admin.wizard.pro.subscription.update"}}
|
||||
title="admin.wizard.subscription.subscription.update"
|
||||
label="admin.wizard.subscription.subscription.update"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
|||
|
||||
{{#if 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>
|
||||
{{/if}}
|
||||
</div>
|
|
@ -1,8 +1,8 @@
|
|||
@import "wizard-mapper";
|
||||
@import "wizard-manager";
|
||||
@import "wizard-api";
|
||||
@import "wizard/mapper";
|
||||
@import "wizard/manager";
|
||||
@import "wizard/api";
|
||||
@import "common/components/buttons";
|
||||
@import "wizard-variables";
|
||||
@import "wizard/variables";
|
||||
|
||||
.admin-wizard-controls {
|
||||
display: flex;
|
||||
|
@ -121,7 +121,7 @@
|
|||
}
|
||||
|
||||
.wizard-settings-parent {
|
||||
padding: 20px;
|
||||
padding: 1em;
|
||||
border: 1px solid var(--primary-low);
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,7 @@
|
|||
|
||||
.wizard-basic-details,
|
||||
.wizard-custom-field,
|
||||
.advanced-settings {
|
||||
.subscription-settings {
|
||||
@extend .wizard-settings-group;
|
||||
}
|
||||
|
||||
|
@ -411,7 +411,7 @@
|
|||
margin-top: 5px;
|
||||
}
|
||||
|
||||
&.pro {
|
||||
&.subscription {
|
||||
.setting-label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -423,15 +423,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.advanced-settings {
|
||||
width: 100%;
|
||||
margin-top: 30px;
|
||||
|
||||
[class~="setting"]:first-of-type {
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
|
||||
.wizard-custom-action > [class~="setting"]:first-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
@ -735,7 +726,7 @@
|
|||
flex-wrap: wrap;
|
||||
|
||||
> li {
|
||||
background-color: var(--primary-low);
|
||||
border: 1px solid var(--primary);
|
||||
padding: 1em;
|
||||
margin: 0 0 1em 0;
|
||||
|
||||
|
@ -797,12 +788,12 @@
|
|||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.pro-label {
|
||||
.subscription-label {
|
||||
color: var(--tertiary);
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
.admin-wizards-pro {
|
||||
.admin-wizards-subscription {
|
||||
.admin-wizard-controls {
|
||||
h3,
|
||||
label {
|
||||
|
@ -826,7 +817,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.custom-wizard-pro-subscription {
|
||||
.custom-wizard-subscription {
|
||||
.title-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
@ -861,19 +852,19 @@
|
|||
}
|
||||
}
|
||||
|
||||
.wizard-pro-selector.select-kit.single-select {
|
||||
.wizard-subscription-selector.select-kit.single-select {
|
||||
.select-kit-row .texts {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.pro-label {
|
||||
.subscription-label {
|
||||
margin-left: 0.75em;
|
||||
padding-top: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
.btn.btn-pavilion-pro {
|
||||
.btn.btn-pavilion-support {
|
||||
background: var(--pavilion-primary);
|
||||
color: var(--pavilion-secondary);
|
||||
|
||||
|
@ -883,11 +874,108 @@
|
|||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background: darken($pavilionPrimary, 5%);
|
||||
background: darken($pavilion_primary, 5%);
|
||||
|
||||
&[href],
|
||||
svg.d-icon {
|
||||
color: darken($pavilionSecondary, 10%);
|
||||
color: darken($pavilion_secondary, 10%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.subscription-container {
|
||||
width: 100%;
|
||||
padding: 1em;
|
||||
background-color: rgba($pavilion_primary, 0.1);
|
||||
|
||||
.subscription-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1em;
|
||||
|
||||
h3 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--pavilion-primary);
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.subscribed) .subscription-settings {
|
||||
filter: blur(1px);
|
||||
}
|
||||
}
|
||||
|
||||
.wizard-notice {
|
||||
padding: 1em;
|
||||
margin-bottom: 1em;
|
||||
border: 1px solid var(--primary);
|
||||
border-radius: 4px;
|
||||
position: relative;
|
||||
|
||||
&.dismissed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.d-icon {
|
||||
margin-right: .4em;
|
||||
}
|
||||
|
||||
.notice-header {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.notice-badge {
|
||||
border: 1px solid var(--primary);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0 .5em;
|
||||
border-radius: 4px;
|
||||
margin-right: 1em;
|
||||
font-size: .9em;
|
||||
line-height: 25px;
|
||||
min-height: 25px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.warning {
|
||||
.notice-expired-at {
|
||||
border: 1px solid var(--success);
|
||||
background-color: rgba($success, 0.1);
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.notice-title {
|
||||
border: 1px solid var(--pavilion-warning);
|
||||
background-color: rgba($pavilion_warning, 0.1);
|
||||
color: var(--pavilion-warning);
|
||||
}
|
||||
}
|
||||
|
||||
.notice-issued {
|
||||
margin-right: .3em;
|
||||
}
|
||||
|
||||
.notice-message {
|
||||
p {
|
||||
margin: .5em 0;
|
||||
}
|
||||
|
||||
p:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dismiss-notice,
|
||||
.spinner {
|
||||
position: absolute;
|
||||
top: 1em;
|
||||
right: 1em;
|
||||
color: var(--primary);
|
||||
}
|
||||
}
|
9
assets/stylesheets/admin/wizard/variables.scss
Normale Datei
9
assets/stylesheets/admin/wizard/variables.scss
Normale Datei
|
@ -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};
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
$pavilionPrimary: #3c1c8c;
|
||||
$pavilionSecondary: #ffffff;
|
||||
|
||||
:root {
|
||||
--pavilion-primary: #3c1c8c;
|
||||
--pavilion-secondary: #ffffff;
|
||||
}
|
|
@ -60,9 +60,9 @@ en:
|
|||
expand_text: "Read More"
|
||||
collapse_text: "Show Less"
|
||||
|
||||
pro_support_button:
|
||||
title: "Request Pro Support"
|
||||
label: "Pro Support"
|
||||
support_button:
|
||||
title: "Request Support"
|
||||
label: "Support"
|
||||
|
||||
message:
|
||||
wizard:
|
||||
|
@ -95,10 +95,10 @@ en:
|
|||
destroying: Destroying wizards...
|
||||
import_complete: Import complete
|
||||
destroy_complete: Destruction complete
|
||||
pro:
|
||||
documentation: Check out the PRO documentation
|
||||
authorize: "Authorize this forum to use your PRO subscription plan on %{server}."
|
||||
not_subscribed: "You've authorized, but are not currently subscribed to a PRO plan on %{server}."
|
||||
subscription:
|
||||
documentation: Check out the subscription documentation
|
||||
authorize: "Authorize this forum to use your Custom Wizard subscription plan on %{server}."
|
||||
not_subscribed: "You've authorized, but are not currently subscribed to a Custom Wizard plan on %{server}."
|
||||
subscription_expiring: "Your subscription is active, but will expire in the next 48 hours."
|
||||
subscription_active: "Your subscription is active."
|
||||
subscription_inactive: "Your subscription is inactive on this forum. Read more in <a href='https://thepavilion.io/t/3652'>the documentation</a>."
|
||||
|
@ -455,10 +455,19 @@ en:
|
|||
destroy: Destroy
|
||||
destroyed: destroyed
|
||||
|
||||
pro:
|
||||
nav_label: PRO
|
||||
label: PRO
|
||||
title: Custom Wizard PRO
|
||||
subscription_container:
|
||||
title: Subscriber Features
|
||||
subscribed:
|
||||
label: Subscribed
|
||||
title: You're subscribed and can use these features
|
||||
not_subscribed:
|
||||
label: Not Subscribed
|
||||
title: Subscribe to use these features
|
||||
|
||||
subscription:
|
||||
nav_label: Subscription
|
||||
label: Subscription
|
||||
title: Custom Wizard Subscription
|
||||
authorize: Authorize
|
||||
authorized: Authorized
|
||||
unauthorize: cancel
|
||||
|
@ -471,7 +480,14 @@ en:
|
|||
active: Active
|
||||
inactive: Inactive
|
||||
update: Update
|
||||
last_updated: Last updated
|
||||
last_updated: Last updated
|
||||
|
||||
notice:
|
||||
plugin: Custom Wizard Plugin
|
||||
issued: Issued
|
||||
resolved: Resolved
|
||||
title:
|
||||
warning: Warning Notice
|
||||
|
||||
wizard_js:
|
||||
group:
|
||||
|
|
|
@ -17,7 +17,7 @@ en:
|
|||
name_too_short: "'%{name}' is too short for a custom field name (min length is #{min_length})"
|
||||
name_already_taken: "'%{name}' is already taken as a custom field name"
|
||||
save_default: "Failed to save custom field '%{name}'"
|
||||
pro_type: "%{type} custom fields require PRO Subscription"
|
||||
subscription_type: "%{type} custom fields require a subscription"
|
||||
|
||||
field:
|
||||
too_short: "%{label} must be at least %{min} characters"
|
||||
|
@ -50,7 +50,16 @@ en:
|
|||
required: "%{property} is required"
|
||||
conflict: "Wizard with id '%{wizard_id}' already exists"
|
||||
after_time: "After time setting is invalid"
|
||||
pro: "%{type} %{property} is PRO only"
|
||||
subscription: "%{type} %{property} is subscription only"
|
||||
|
||||
notice:
|
||||
connection_error: "Failed to connect to [%{server}](http://%{server})"
|
||||
compatibility_issue: >
|
||||
The Custom Wizard Plugin may have a compatibility issue with the latest version of Discourse.
|
||||
Please check the Custom Wizard Plugin status on [%{server}](http://%{server}) before updating Discourse.
|
||||
plugin_status_connection_error_limit: >
|
||||
We're unable to connect to the plugin status server to determine whether there are any compatibility issues with the latest version of Discourse.
|
||||
Please contact <a href="mailto:support@thepavilion.io">support@thepavilion.io</a> for further assistance.
|
||||
|
||||
site_settings:
|
||||
custom_wizard_enabled: "Enable custom wizards."
|
||||
|
|
|
@ -45,10 +45,13 @@ Discourse::Application.routes.append do
|
|||
post 'admin/wizards/manager/import' => 'admin_manager#import'
|
||||
delete 'admin/wizards/manager/destroy' => 'admin_manager#destroy'
|
||||
|
||||
get 'admin/wizards/pro' => 'admin_pro#index'
|
||||
get 'admin/wizards/pro/authorize' => 'admin_pro#authorize'
|
||||
get 'admin/wizards/pro/authorize/callback' => 'admin_pro#authorize_callback'
|
||||
delete 'admin/wizards/pro/authorize' => 'admin_pro#destroy_authentication'
|
||||
post 'admin/wizards/pro/subscription' => 'admin_pro#update_subscription'
|
||||
get 'admin/wizards/subscription' => 'admin_subscription#index'
|
||||
post 'admin/wizards/subscription' => 'admin_subscription#update_subscription'
|
||||
get 'admin/wizards/subscription/authorize' => 'admin_subscription#authorize'
|
||||
get 'admin/wizards/subscription/authorize/callback' => 'admin_subscription#authorize_callback'
|
||||
delete 'admin/wizards/subscription/authorize' => 'admin_subscription#destroy_authentication'
|
||||
|
||||
get 'admin/wizards/notice' => 'admin_notice#index'
|
||||
put 'admin/wizards/notice/:notice_id' => 'admin_notice#dismiss'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,6 +3,12 @@ class CustomWizard::AdminController < ::Admin::AdminController
|
|||
before_action :ensure_admin
|
||||
|
||||
def index
|
||||
render_json_dump(
|
||||
notices: ActiveModel::ArraySerializer.new(
|
||||
CustomWizard::Notice.list,
|
||||
each_serializer: CustomWizard::NoticeSerializer
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -3,7 +3,7 @@ class CustomWizard::AdminCustomFieldsController < CustomWizard::AdminController
|
|||
def index
|
||||
render_json_dump(
|
||||
custom_fields: custom_field_list,
|
||||
pro_subscribed: CustomWizard::Pro.subscribed?
|
||||
subscribed: CustomWizard::Subscription.subscribed?
|
||||
)
|
||||
end
|
||||
|
||||
|
|
22
controllers/custom_wizard/admin/notice.rb
Normale Datei
22
controllers/custom_wizard/admin/notice.rb
Normale Datei
|
@ -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
|
|
@ -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
|
48
controllers/custom_wizard/admin/subscription.rb
Normale Datei
48
controllers/custom_wizard/admin/subscription.rb
Normale Datei
|
@ -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
|
|
@ -11,7 +11,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
|||
field_types: CustomWizard::Field.types,
|
||||
realtime_validations: CustomWizard::RealtimeValidation.types,
|
||||
custom_fields: custom_field_list,
|
||||
pro_subscribed: CustomWizard::Pro.subscribed?
|
||||
subscribed: CustomWizard::Subscription.subscribed?
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ class CustomWizard::WizardController < ::ApplicationController
|
|||
layout 'wizard'
|
||||
|
||||
before_action :ensure_plugin_enabled
|
||||
before_action :update_pro_subscription, only: [:index]
|
||||
before_action :update_subscription, only: [:index]
|
||||
helper_method :wizard_page_title
|
||||
helper_method :wizard_theme_id
|
||||
helper_method :wizard_theme_lookup
|
||||
|
@ -84,7 +84,7 @@ class CustomWizard::WizardController < ::ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def update_pro_subscription
|
||||
CustomWizard::Pro.update_subscription
|
||||
def update_subscription
|
||||
CustomWizard::Subscription.update
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"result": {
|
||||
"line": 92.14
|
||||
"line": 92.3
|
||||
}
|
||||
}
|
||||
|
|
9
jobs/scheduled/custom_wizard/update_notices.rb
Normale Datei
9
jobs/scheduled/custom_wizard/update_notices.rb
Normale Datei
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Jobs::CustomWizardUpdateNotices < ::Jobs::Scheduled
|
||||
every 5.minutes
|
||||
|
||||
def execute(args = {})
|
||||
CustomWizard::Notice.update
|
||||
end
|
||||
end
|
9
jobs/scheduled/custom_wizard/update_subscription.rb
Normale Datei
9
jobs/scheduled/custom_wizard/update_subscription.rb
Normale Datei
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Jobs::CustomWizardUpdateSubscription < ::Jobs::Scheduled
|
||||
every 1.hour
|
||||
|
||||
def execute(args = {})
|
||||
CustomWizard::Subscription.update
|
||||
end
|
||||
end
|
|
@ -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
|
|
@ -749,8 +749,4 @@ class CustomWizard::Action
|
|||
@log.join('; ')
|
||||
)
|
||||
end
|
||||
|
||||
def pro_actions
|
||||
%w[send_message watch_categories send_to_api create_group create_category]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,9 +17,9 @@ class ::CustomWizard::CustomField
|
|||
category: ["basic_category"],
|
||||
post: ["post"]
|
||||
}
|
||||
PRO_CLASSES ||= ['category', 'group']
|
||||
SUBSCRIPTION_CLASSES ||= ['category', 'group']
|
||||
TYPES ||= ["string", "boolean", "integer", "json"]
|
||||
PRO_TYPES ||= ["json"]
|
||||
SUBSCRIPTION_TYPES ||= ["json"]
|
||||
LIST_CACHE_KEY ||= 'custom_field_list'
|
||||
|
||||
def self.serializers
|
||||
|
@ -40,7 +40,7 @@ class ::CustomWizard::CustomField
|
|||
end
|
||||
end
|
||||
|
||||
@pro = CustomWizard::Pro.new
|
||||
@subscription = CustomWizard::Subscription.new
|
||||
end
|
||||
|
||||
def save
|
||||
|
@ -85,8 +85,8 @@ class ::CustomWizard::CustomField
|
|||
next
|
||||
end
|
||||
|
||||
if attr == 'klass' && PRO_CLASSES.include?(value) && !@pro.subscribed?
|
||||
add_error(I18n.t("wizard.custom_field.error.pro_type", type: value))
|
||||
if attr == 'klass' && SUBSCRIPTION_CLASSES.include?(value) && !@subscription.subscribed?
|
||||
add_error(I18n.t("wizard.custom_field.error.subscription_type", type: value))
|
||||
end
|
||||
|
||||
if attr == 'serializers' && (unsupported = value - CLASSES[klass.to_sym]).length > 0
|
||||
|
@ -100,8 +100,8 @@ class ::CustomWizard::CustomField
|
|||
add_error(I18n.t("#{i18n_key}.unsupported_type", type: value))
|
||||
end
|
||||
|
||||
if attr == 'type' && PRO_TYPES.include?(value) && !@pro.subscribed?
|
||||
add_error(I18n.t("wizard.custom_field.error.pro_type", type: value))
|
||||
if attr == 'type' && SUBSCRIPTION_TYPES.include?(value) && !@subscription.subscribed?
|
||||
add_error(I18n.t("wizard.custom_field.error.subscription_type", type: value))
|
||||
end
|
||||
|
||||
if attr == 'name'
|
||||
|
|
|
@ -47,7 +47,7 @@ class CustomWizard::Mapper
|
|||
@data = params[:data] || {}
|
||||
@user = params[:user]
|
||||
@opts = params[:opts] || {}
|
||||
@pro = CustomWizard::Pro.new
|
||||
@subscription = CustomWizard::Subscription.new
|
||||
end
|
||||
|
||||
def perform
|
||||
|
@ -252,7 +252,7 @@ class CustomWizard::Mapper
|
|||
end
|
||||
end
|
||||
|
||||
if opts[:template] && @pro.subscribed?
|
||||
if opts[:template] && @subscription.subscribed?
|
||||
template = Liquid::Template.parse(string)
|
||||
string = template.render(data)
|
||||
end
|
||||
|
|
234
lib/custom_wizard/notice.rb
Normale Datei
234
lib/custom_wizard/notice.rb
Normale Datei
|
@ -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
|
|
@ -1,14 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CustomWizard::Pro
|
||||
class CustomWizard::Subscription
|
||||
include ActiveModel::Serialization
|
||||
|
||||
attr_accessor :authentication,
|
||||
:subscription
|
||||
|
||||
def initialize
|
||||
@authentication = CustomWizard::ProAuthentication.new(get_authentication)
|
||||
@subscription = CustomWizard::ProSubscription.new(get_subscription)
|
||||
@authentication = CustomWizard::Subscription::Authentication.new(get_authentication)
|
||||
@subscription = CustomWizard::Subscription::Subscription.new(get_subscription)
|
||||
end
|
||||
|
||||
def authorized?
|
||||
|
@ -35,7 +35,7 @@ class CustomWizard::Pro
|
|||
"discourse-subscription-server:user_subscription"
|
||||
end
|
||||
|
||||
def update_subscription
|
||||
def update
|
||||
if @authentication.active?
|
||||
response = Excon.get(
|
||||
"https://#{server}/subscription-server/user-subscriptions/#{subscription_type}/#{client_name}",
|
||||
|
@ -67,7 +67,7 @@ class CustomWizard::Pro
|
|||
|
||||
def destroy_subscription
|
||||
if remove_subscription
|
||||
@subscription = CustomWizard::ProSubscription.new(get_subscription)
|
||||
@subscription = CustomWizard::Subscription::Subscription.new(get_subscription)
|
||||
!@subscription.active?
|
||||
else
|
||||
false
|
||||
|
@ -80,7 +80,7 @@ class CustomWizard::Pro
|
|||
public_key: keys.public_key,
|
||||
nonce: keys.nonce,
|
||||
client_id: @authentication.client_id,
|
||||
auth_redirect: "#{Discourse.base_url}/admin/wizards/pro/authorize/callback",
|
||||
auth_redirect: "#{Discourse.base_url}/admin/wizards/subscription/authorize/callback",
|
||||
application_name: SiteSetting.title,
|
||||
scopes: scope
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ class CustomWizard::Pro
|
|||
|
||||
def destroy_authentication
|
||||
if remove_authentication
|
||||
@authentication = CustomWizard::ProAuthentication.new(get_authentication)
|
||||
@authentication = CustomWizard::Subscription::Authentication.new(get_authentication)
|
||||
!@authentication.active?
|
||||
else
|
||||
false
|
||||
|
@ -123,12 +123,12 @@ class CustomWizard::Pro
|
|||
self.new.authorized?
|
||||
end
|
||||
|
||||
def self.update_subscription
|
||||
self.new.update_subscription
|
||||
def self.update
|
||||
self.new.update
|
||||
end
|
||||
|
||||
def self.namespace
|
||||
"custom_wizard_pro"
|
||||
"custom_wizard_subscription"
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -157,8 +157,8 @@ class CustomWizard::Pro
|
|||
end
|
||||
|
||||
def set_subscription(type)
|
||||
PluginStore.set(CustomWizard::Pro.namespace, subscription_db_key, type: type, updated_at: Time.now)
|
||||
CustomWizard::ProSubscription.new(get_subscription)
|
||||
PluginStore.set(CustomWizard::Subscription.namespace, subscription_db_key, type: type, updated_at: Time.now)
|
||||
CustomWizard::Subscription::Subscription.new(get_subscription)
|
||||
end
|
||||
|
||||
def get_authentication
|
||||
|
@ -176,7 +176,7 @@ class CustomWizard::Pro
|
|||
auth_by: user_id,
|
||||
auth_at: Time.now
|
||||
)
|
||||
CustomWizard::ProAuthentication.new(get_authentication)
|
||||
CustomWizard::Subscription::Authentication.new(get_authentication)
|
||||
end
|
||||
|
||||
def remove_authentication
|
|
@ -1,5 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
class CustomWizard::ProAuthentication
|
||||
class CustomWizard::Subscription::Authentication
|
||||
include ActiveModel::Serialization
|
||||
|
||||
attr_reader :client_id,
|
||||
|
@ -53,7 +53,7 @@ class CustomWizard::ProAuthentication
|
|||
end
|
||||
|
||||
def get_keys(request_id)
|
||||
raw = PluginStore.get(CustomWizard::Pro.namespace, "#{keys_db_key}_#{request_id}")
|
||||
raw = PluginStore.get(CustomWizard::Subscription.namespace, "#{keys_db_key}_#{request_id}")
|
||||
OpenStruct.new(
|
||||
user_id: raw && raw['user_id'],
|
||||
pem: raw && raw['pem'],
|
||||
|
@ -72,7 +72,7 @@ class CustomWizard::ProAuthentication
|
|||
end
|
||||
|
||||
def set_keys(request_id, user_id, rsa, nonce)
|
||||
PluginStore.set(CustomWizard::Pro.namespace, "#{keys_db_key}_#{request_id}",
|
||||
PluginStore.set(CustomWizard::Subscription.namespace, "#{keys_db_key}_#{request_id}",
|
||||
user_id: user_id,
|
||||
pem: rsa.export,
|
||||
nonce: nonce
|
||||
|
@ -80,16 +80,16 @@ class CustomWizard::ProAuthentication
|
|||
end
|
||||
|
||||
def delete_keys(request_id)
|
||||
PluginStore.remove(CustomWizard::Pro.namespace, "#{keys_db_key}_#{request_id}")
|
||||
PluginStore.remove(CustomWizard::Subscription.namespace, "#{keys_db_key}_#{request_id}")
|
||||
end
|
||||
|
||||
def get_client_id
|
||||
PluginStore.get(CustomWizard::Pro.namespace, client_id_db_key)
|
||||
PluginStore.get(CustomWizard::Subscription.namespace, client_id_db_key)
|
||||
end
|
||||
|
||||
def set_client_id
|
||||
client_id = SecureRandom.hex(32)
|
||||
PluginStore.set(CustomWizard::Pro.namespace, client_id_db_key, client_id)
|
||||
PluginStore.set(CustomWizard::Subscription.namespace, client_id_db_key, client_id)
|
||||
client_id
|
||||
end
|
||||
end
|
|
@ -1,5 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
class CustomWizard::ProSubscription
|
||||
class CustomWizard::Subscription::Subscription
|
||||
include ActiveModel::Serialization
|
||||
|
||||
attr_reader :type,
|
|
@ -6,7 +6,7 @@ class CustomWizard::TemplateValidator
|
|||
def initialize(data, opts = {})
|
||||
@data = data
|
||||
@opts = opts
|
||||
@pro = CustomWizard::Pro.new
|
||||
@subscription = CustomWizard::Subscription.new
|
||||
end
|
||||
|
||||
def perform
|
||||
|
@ -15,15 +15,15 @@ class CustomWizard::TemplateValidator
|
|||
check_id(data, :wizard)
|
||||
check_required(data, :wizard)
|
||||
validate_after_time
|
||||
validate_pro(data, :wizard)
|
||||
validate_subscription(data, :wizard)
|
||||
|
||||
data[:steps].each do |step|
|
||||
check_required(step, :step)
|
||||
validate_pro(step, :step)
|
||||
validate_subscription(step, :step)
|
||||
|
||||
if step[:fields].present?
|
||||
step[:fields].each do |field|
|
||||
validate_pro(field, :field)
|
||||
validate_subscription(field, :field)
|
||||
check_required(field, :field)
|
||||
end
|
||||
end
|
||||
|
@ -31,7 +31,7 @@ class CustomWizard::TemplateValidator
|
|||
|
||||
if data[:actions].present?
|
||||
data[:actions].each do |action|
|
||||
validate_pro(action, :action)
|
||||
validate_subscription(action, :action)
|
||||
check_required(action, :action)
|
||||
end
|
||||
end
|
||||
|
@ -52,7 +52,7 @@ class CustomWizard::TemplateValidator
|
|||
}
|
||||
end
|
||||
|
||||
def self.pro
|
||||
def self.subscription
|
||||
{
|
||||
wizard: {
|
||||
save_submissions: 'false',
|
||||
|
@ -90,18 +90,18 @@ class CustomWizard::TemplateValidator
|
|||
end
|
||||
end
|
||||
|
||||
def validate_pro(object, type)
|
||||
self.class.pro[type].each do |property, pro_type|
|
||||
def validate_subscription(object, type)
|
||||
self.class.subscription[type].each do |property, subscription_type|
|
||||
val = object[property.to_s]
|
||||
is_pro = (val != nil) && (
|
||||
pro_type === 'present' && val.present? ||
|
||||
(['true', 'false'].include?(pro_type) && cast_bool(val) == cast_bool(pro_type)) ||
|
||||
(pro_type === 'conditional' && val.is_a?(Hash)) ||
|
||||
(pro_type.is_a?(Array) && pro_type.include?(val))
|
||||
is_subscription = (val != nil) && (
|
||||
subscription_type === 'present' && val.present? ||
|
||||
(['true', 'false'].include?(subscription_type) && cast_bool(val) == cast_bool(subscription_type)) ||
|
||||
(subscription_type === 'conditional' && val.is_a?(Hash)) ||
|
||||
(subscription_type.is_a?(Array) && subscription_type.include?(val))
|
||||
)
|
||||
|
||||
if is_pro && !@pro.subscribed?
|
||||
errors.add :base, I18n.t("wizard.validation.pro", type: type.to_s, property: property)
|
||||
if is_subscription && !@subscription.subscribed?
|
||||
errors.add :base, I18n.t("wizard.validation.subscription", type: type.to_s, property: property)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
31
plugin.rb
31
plugin.rb
|
@ -7,9 +7,7 @@
|
|||
# contact emails: angus@thepavilion.io
|
||||
|
||||
gem 'liquid', '5.0.1', require: true
|
||||
register_asset 'stylesheets/common/wizard-admin.scss'
|
||||
register_asset 'stylesheets/common/wizard-mapper.scss'
|
||||
|
||||
register_asset 'stylesheets/admin/admin.scss', :desktop
|
||||
enabled_site_setting :custom_wizard_enabled
|
||||
|
||||
config = Rails.application.config
|
||||
|
@ -42,6 +40,7 @@ if respond_to?(:register_svg_icon)
|
|||
register_svg_icon "comment-alt"
|
||||
register_svg_icon "far-life-ring"
|
||||
register_svg_icon "arrow-right"
|
||||
register_svg_icon "shield-virus"
|
||||
end
|
||||
|
||||
class ::Sprockets::DirectiveProcessor
|
||||
|
@ -71,13 +70,15 @@ after_initialize do
|
|||
../controllers/custom_wizard/admin/logs.rb
|
||||
../controllers/custom_wizard/admin/manager.rb
|
||||
../controllers/custom_wizard/admin/custom_fields.rb
|
||||
../controllers/custom_wizard/admin/pro.rb
|
||||
../controllers/custom_wizard/admin/subscription.rb
|
||||
../controllers/custom_wizard/admin/notice.rb
|
||||
../controllers/custom_wizard/wizard.rb
|
||||
../controllers/custom_wizard/steps.rb
|
||||
../controllers/custom_wizard/realtime_validations.rb
|
||||
../jobs/regular/refresh_api_access_token.rb
|
||||
../jobs/regular/set_after_time_wizard.rb
|
||||
../jobs/scheduled/update_pro_subscription.rb
|
||||
../jobs/scheduled/custom_wizard/update_subscription.rb
|
||||
../jobs/scheduled/custom_wizard/update_notices.rb
|
||||
../lib/custom_wizard/validators/template.rb
|
||||
../lib/custom_wizard/validators/update.rb
|
||||
../lib/custom_wizard/action_result.rb
|
||||
|
@ -96,9 +97,10 @@ after_initialize do
|
|||
../lib/custom_wizard/submission.rb
|
||||
../lib/custom_wizard/template.rb
|
||||
../lib/custom_wizard/wizard.rb
|
||||
../lib/custom_wizard/pro.rb
|
||||
../lib/custom_wizard/pro/subscription.rb
|
||||
../lib/custom_wizard/pro/authentication.rb
|
||||
../lib/custom_wizard/notice.rb
|
||||
../lib/custom_wizard/subscription.rb
|
||||
../lib/custom_wizard/subscription/subscription.rb
|
||||
../lib/custom_wizard/subscription/authentication.rb
|
||||
../lib/custom_wizard/api/api.rb
|
||||
../lib/custom_wizard/api/authorization.rb
|
||||
../lib/custom_wizard/api/endpoint.rb
|
||||
|
@ -119,9 +121,10 @@ after_initialize do
|
|||
../serializers/custom_wizard/log_serializer.rb
|
||||
../serializers/custom_wizard/submission_serializer.rb
|
||||
../serializers/custom_wizard/realtime_validation/similar_topics_serializer.rb
|
||||
../serializers/custom_wizard/pro/authentication_serializer.rb
|
||||
../serializers/custom_wizard/pro/subscription_serializer.rb
|
||||
../serializers/custom_wizard/pro_serializer.rb
|
||||
../serializers/custom_wizard/subscription/authentication_serializer.rb
|
||||
../serializers/custom_wizard/subscription/subscription_serializer.rb
|
||||
../serializers/custom_wizard/subscription_serializer.rb
|
||||
../serializers/custom_wizard/notice_serializer.rb
|
||||
../extensions/extra_locales_controller.rb
|
||||
../extensions/invites_controller.rb
|
||||
../extensions/users_controller.rb
|
||||
|
@ -238,5 +241,11 @@ after_initialize do
|
|||
"#{serializer_klass}_serializer".classify.constantize.prepend CustomWizardCustomFieldSerializer
|
||||
end
|
||||
|
||||
AdminDashboardData.add_problem_check do
|
||||
warning_notices = CustomWizard::Notice.list(CustomWizard::Notice.types[:warning])
|
||||
warning_notices.any? ? ActionView::Base.full_sanitizer.sanitize(warning_notices.first.message, tags: %w(a)) : nil
|
||||
end
|
||||
|
||||
Jobs.enqueue(:custom_wizard_update_notices)
|
||||
DiscourseEvent.trigger(:custom_wizard_ready)
|
||||
end
|
||||
|
|
20
serializers/custom_wizard/notice_serializer.rb
Normale Datei
20
serializers/custom_wizard/notice_serializer.rb
Normale Datei
|
@ -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
|
|
@ -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
|
|
@ -1,5 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
class CustomWizard::ProAuthenticationSerializer < ApplicationSerializer
|
||||
class CustomWizard::Subscription::AuthenticationSerializer < ApplicationSerializer
|
||||
attributes :active,
|
||||
:client_id,
|
||||
:auth_by,
|
|
@ -1,5 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
class CustomWizard::ProSubscriptionSerializer < ApplicationSerializer
|
||||
class CustomWizard::Subscription::SubscriptionSerializer < ApplicationSerializer
|
||||
attributes :type,
|
||||
:active,
|
||||
:updated_at
|
6
serializers/custom_wizard/subscription_serializer.rb
Normale Datei
6
serializers/custom_wizard/subscription_serializer.rb
Normale Datei
|
@ -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
|
|
@ -123,6 +123,6 @@ class CustomWizard::FieldSerializer < ::ApplicationSerializer
|
|||
end
|
||||
|
||||
def subscribed?
|
||||
@subscribed ||= CustomWizard::Pro.subscribed?
|
||||
@subscribed ||= CustomWizard::Subscription.subscribed?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,7 +10,7 @@ class CustomWizard::WizardSerializer < CustomWizard::BasicWizardSerializer
|
|||
:permitted,
|
||||
:uncategorized_category_id,
|
||||
:categories,
|
||||
:pro_subscribed
|
||||
:subscribed
|
||||
|
||||
has_many :steps, serializer: ::CustomWizard::StepSerializer, embed: :objects
|
||||
has_one :user, serializer: ::BasicUserSerializer, embed: :objects
|
||||
|
@ -62,7 +62,7 @@ class CustomWizard::WizardSerializer < CustomWizard::BasicWizardSerializer
|
|||
object.categories.map { |c| c.to_h }
|
||||
end
|
||||
|
||||
def pro_subscribed
|
||||
CustomWizard::Pro.subscribed?
|
||||
def subscribed
|
||||
CustomWizard::Subscription.subscribed?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -80,8 +80,4 @@ class CustomWizard::StepSerializer < ::ApplicationSerializer
|
|||
def i18n_key
|
||||
@i18n_key ||= "#{object.wizard.id}.#{object.id}".underscore
|
||||
end
|
||||
|
||||
def subscribed?
|
||||
@subscribed ||= CustomWizard::Pro.subscribed?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -174,7 +174,7 @@ describe CustomWizard::Action do
|
|||
expect(updater.result[:redirect_on_next]).to eq("https://google.com")
|
||||
end
|
||||
|
||||
context "pro actions" do
|
||||
context "subscription actions" do
|
||||
before do
|
||||
enable_subscription
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ require_relative '../../plugin_helper'
|
|||
|
||||
describe CustomWizard::CustomField do
|
||||
let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") }
|
||||
let(:custom_field_pro_json) { get_wizard_fixture("custom_field/pro_custom_fields") }
|
||||
let(:custom_field_subscription_json) { get_wizard_fixture("custom_field/subscription_custom_fields") }
|
||||
|
||||
before do
|
||||
CustomWizard::CustomField.invalidate_cache
|
||||
|
@ -193,44 +193,44 @@ describe CustomWizard::CustomField do
|
|||
).to eq(false)
|
||||
end
|
||||
|
||||
it "does not save pro field types without a pro subscription" do
|
||||
pro_field_json = custom_field_pro_json['custom_fields'].first
|
||||
custom_field = CustomWizard::CustomField.new(nil, pro_field_json)
|
||||
it "does not save subscription field types without a subscription" do
|
||||
subscription_field_json = custom_field_subscription_json['custom_fields'].first
|
||||
custom_field = CustomWizard::CustomField.new(nil, subscription_field_json)
|
||||
|
||||
expect(custom_field.save).to eq(false)
|
||||
expect(custom_field.valid?).to eq(false)
|
||||
expect(custom_field.errors.full_messages.first).to eq(
|
||||
I18n.t("wizard.custom_field.error.pro_type", type: "json")
|
||||
I18n.t("wizard.custom_field.error.subscription_type", type: "json")
|
||||
)
|
||||
end
|
||||
|
||||
it "does not save pro field classes without a pro subscription" do
|
||||
pro_field_json = custom_field_pro_json['custom_fields'].second
|
||||
custom_field = CustomWizard::CustomField.new(nil, pro_field_json)
|
||||
it "does not save subscription field classes without a subscription" do
|
||||
subscription_field_json = custom_field_subscription_json['custom_fields'].second
|
||||
custom_field = CustomWizard::CustomField.new(nil, subscription_field_json)
|
||||
|
||||
expect(custom_field.save).to eq(false)
|
||||
expect(custom_field.valid?).to eq(false)
|
||||
expect(custom_field.errors.full_messages.first).to eq(
|
||||
I18n.t("wizard.custom_field.error.pro_type", type: "category")
|
||||
I18n.t("wizard.custom_field.error.subscription_type", type: "category")
|
||||
)
|
||||
end
|
||||
|
||||
context "with a pro subscription" do
|
||||
context "with a subscription" do
|
||||
before do
|
||||
enable_subscription
|
||||
end
|
||||
|
||||
it "saves pro field types" do
|
||||
pro_field_json = custom_field_pro_json['custom_fields'].first
|
||||
custom_field = CustomWizard::CustomField.new(nil, pro_field_json)
|
||||
it "saves subscription field types" do
|
||||
subscription_field_json = custom_field_subscription_json['custom_fields'].first
|
||||
custom_field = CustomWizard::CustomField.new(nil, subscription_field_json)
|
||||
|
||||
expect(custom_field.save).to eq(true)
|
||||
expect(custom_field.valid?).to eq(true)
|
||||
end
|
||||
|
||||
it "saves pro field classes" do
|
||||
pro_field_json = custom_field_pro_json['custom_fields'].second
|
||||
custom_field = CustomWizard::CustomField.new(nil, pro_field_json)
|
||||
it "saves subscription field classes" do
|
||||
subscription_field_json = custom_field_subscription_json['custom_fields'].second
|
||||
custom_field = CustomWizard::CustomField.new(nil, subscription_field_json)
|
||||
|
||||
expect(custom_field.save).to eq(true)
|
||||
expect(custom_field.valid?).to eq(true)
|
||||
|
|
|
@ -344,7 +344,7 @@ describe CustomWizard::Mapper do
|
|||
expect(result).to eq(template_params["step_1_field_1"])
|
||||
end
|
||||
|
||||
it "requires a pro subscription" do
|
||||
it "requires a subscription" do
|
||||
template = '{{ "w{step_1_field_1}" | size }}'
|
||||
mapper = create_template_mapper(template_params, user1)
|
||||
result = mapper.interpolate(
|
||||
|
@ -357,7 +357,7 @@ describe CustomWizard::Mapper do
|
|||
expect(result).to eq("{{ \"#{template_params["step_1_field_1"]}\" | size }}")
|
||||
end
|
||||
|
||||
context "with a pro subscription" do
|
||||
context "with a subscription" do
|
||||
before do
|
||||
enable_subscription
|
||||
end
|
||||
|
|
80
spec/components/custom_wizard/notice_spec.rb
Normale Datei
80
spec/components/custom_wizard/notice_spec.rb
Normale Datei
|
@ -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
|
|
@ -2,69 +2,69 @@
|
|||
|
||||
require_relative '../../plugin_helper'
|
||||
|
||||
describe CustomWizard::Pro do
|
||||
describe CustomWizard::Subscription do
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
|
||||
it "initializes pro authentication and subscription" do
|
||||
pro = described_class.new
|
||||
expect(pro.authentication.class).to eq(CustomWizard::ProAuthentication)
|
||||
expect(pro.subscription.class).to eq(CustomWizard::ProSubscription)
|
||||
it "initializes subscription authentication and subscription" do
|
||||
subscription = described_class.new
|
||||
expect(subscription.authentication.class).to eq(CustomWizard::Subscription::Authentication)
|
||||
expect(subscription.subscription.class).to eq(CustomWizard::Subscription::Subscription)
|
||||
end
|
||||
|
||||
it "returns authorized and subscribed states" do
|
||||
pro = described_class.new
|
||||
expect(pro.authorized?).to eq(false)
|
||||
expect(pro.subscribed?).to eq(false)
|
||||
subscription = described_class.new
|
||||
expect(subscription.authorized?).to eq(false)
|
||||
expect(subscription.subscribed?).to eq(false)
|
||||
end
|
||||
|
||||
context "subscription" do
|
||||
before do
|
||||
@pro = described_class.new
|
||||
@subscription = described_class.new
|
||||
end
|
||||
|
||||
it "updates valid subscriptions" do
|
||||
stub_subscription_request(200, valid_subscription)
|
||||
expect(@pro.update_subscription).to eq(true)
|
||||
expect(@pro.subscribed?).to eq(true)
|
||||
expect(@subscription.update).to eq(true)
|
||||
expect(@subscription.subscribed?).to eq(true)
|
||||
end
|
||||
|
||||
it "handles invalid subscriptions" do
|
||||
stub_subscription_request(200, invalid_subscription)
|
||||
expect(@pro.update_subscription).to eq(false)
|
||||
expect(@pro.subscribed?).to eq(false)
|
||||
expect(@subscription.update).to eq(false)
|
||||
expect(@subscription.subscribed?).to eq(false)
|
||||
end
|
||||
|
||||
it "handles subscription http errors" do
|
||||
stub_subscription_request(404, {})
|
||||
expect(@pro.update_subscription).to eq(false)
|
||||
expect(@pro.subscribed?).to eq(false)
|
||||
expect(@subscription.update).to eq(false)
|
||||
expect(@subscription.subscribed?).to eq(false)
|
||||
end
|
||||
|
||||
it "destroys subscriptions" do
|
||||
stub_subscription_request(200, valid_subscription)
|
||||
expect(@pro.update_subscription).to eq(true)
|
||||
expect(@pro.destroy_subscription).to eq(true)
|
||||
expect(@pro.subscribed?).to eq(false)
|
||||
expect(@subscription.update).to eq(true)
|
||||
expect(@subscription.destroy_subscription).to eq(true)
|
||||
expect(@subscription.subscribed?).to eq(false)
|
||||
end
|
||||
|
||||
it "has class aliases" do
|
||||
authenticate_pro
|
||||
authenticate_subscription
|
||||
stub_subscription_request(200, valid_subscription)
|
||||
expect(described_class.update_subscription).to eq(true)
|
||||
expect(described_class.update).to eq(true)
|
||||
expect(described_class.subscribed?).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
context "authentication" do
|
||||
before do
|
||||
@pro = described_class.new
|
||||
@subscription = described_class.new
|
||||
user.update!(admin: true)
|
||||
end
|
||||
|
||||
it "generates a valid authentication request url" do
|
||||
request_id = SecureRandom.hex(32)
|
||||
uri = URI(@pro.authentication_url(user.id, request_id))
|
||||
expect(uri.host).to eq(@pro.server)
|
||||
uri = URI(@subscription.authentication_url(user.id, request_id))
|
||||
expect(uri.host).to eq(@subscription.server)
|
||||
|
||||
parsed_query = Rack::Utils.parse_query uri.query
|
||||
expect(parsed_query['public_key'].present?).to eq(true)
|
||||
|
@ -72,12 +72,12 @@ describe CustomWizard::Pro do
|
|||
expect(parsed_query['client_id'].present?).to eq(true)
|
||||
expect(parsed_query['auth_redirect'].present?).to eq(true)
|
||||
expect(parsed_query['application_name']).to eq(SiteSetting.title)
|
||||
expect(parsed_query['scopes']).to eq(@pro.scope)
|
||||
expect(parsed_query['scopes']).to eq(@subscription.scope)
|
||||
end
|
||||
|
||||
def generate_payload(request_id, user_id)
|
||||
uri = URI(@pro.authentication_url(user_id, request_id))
|
||||
keys = @pro.authentication.get_keys(request_id)
|
||||
uri = URI(@subscription.authentication_url(user_id, request_id))
|
||||
keys = @subscription.authentication.get_keys(request_id)
|
||||
raw_payload = {
|
||||
key: "12345",
|
||||
nonce: keys.nonce,
|
||||
|
@ -92,8 +92,8 @@ describe CustomWizard::Pro do
|
|||
request_id = SecureRandom.hex(32)
|
||||
payload = generate_payload(request_id, user.id)
|
||||
|
||||
expect(@pro.authentication_response(request_id, payload)).to eq(true)
|
||||
expect(@pro.authorized?).to eq(true)
|
||||
expect(@subscription.authentication_response(request_id, payload)).to eq(true)
|
||||
expect(@subscription.authorized?).to eq(true)
|
||||
end
|
||||
|
||||
it "discards authentication response if user who made request as not an admin" do
|
||||
|
@ -102,24 +102,24 @@ describe CustomWizard::Pro do
|
|||
request_id = SecureRandom.hex(32)
|
||||
payload = generate_payload(request_id, user.id)
|
||||
|
||||
expect(@pro.authentication_response(request_id, payload)).to eq(false)
|
||||
expect(@pro.authorized?).to eq(false)
|
||||
expect(@subscription.authentication_response(request_id, payload)).to eq(false)
|
||||
expect(@subscription.authorized?).to eq(false)
|
||||
end
|
||||
|
||||
it "discards authentication response if request_id is invalid" do
|
||||
payload = generate_payload(SecureRandom.hex(32), user.id)
|
||||
|
||||
expect(@pro.authentication_response(SecureRandom.hex(32), payload)).to eq(false)
|
||||
expect(@pro.authorized?).to eq(false)
|
||||
expect(@subscription.authentication_response(SecureRandom.hex(32), payload)).to eq(false)
|
||||
expect(@subscription.authorized?).to eq(false)
|
||||
end
|
||||
|
||||
it "destroys authentication" do
|
||||
request_id = SecureRandom.hex(32)
|
||||
payload = generate_payload(request_id, user.id)
|
||||
@pro.authentication_response(request_id, payload)
|
||||
@subscription.authentication_response(request_id, payload)
|
||||
|
||||
expect(@pro.destroy_authentication).to eq(true)
|
||||
expect(@pro.authorized?).to eq(false)
|
||||
expect(@subscription.destroy_authentication).to eq(true)
|
||||
expect(@subscription.authorized?).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@ describe "custom field extensions" do
|
|||
fab!(:user) { Fabricate(:user) }
|
||||
|
||||
let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") }
|
||||
let(:pro_custom_field_json) { get_wizard_fixture("custom_field/pro_custom_fields") }
|
||||
let(:subscription_custom_field_json) { get_wizard_fixture("custom_field/subscription_custom_fields") }
|
||||
|
||||
before do
|
||||
custom_field_json['custom_fields'].each do |field_json|
|
||||
|
@ -72,11 +72,11 @@ describe "custom field extensions" do
|
|||
end
|
||||
end
|
||||
|
||||
context "pro custom fields" do
|
||||
context "subscription custom fields" do
|
||||
before do
|
||||
enable_subscription
|
||||
|
||||
pro_custom_field_json['custom_fields'].each do |field_json|
|
||||
subscription_custom_field_json['custom_fields'].each do |field_json|
|
||||
custom_field = CustomWizard::CustomField.new(nil, field_json)
|
||||
custom_field.save
|
||||
end
|
||||
|
|
29
spec/jobs/update_notices_spec.rb
Normale Datei
29
spec/jobs/update_notices_spec.rb
Normale Datei
|
@ -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
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
require_relative '../plugin_helper'
|
||||
|
||||
describe CustomWizard::UpdateProSubscription do
|
||||
it "updates the pro subscription" do
|
||||
describe Jobs::CustomWizardUpdateSubscription do
|
||||
it "updates the subscription" do
|
||||
stub_subscription_request(200, valid_subscription)
|
||||
described_class.new.execute
|
||||
expect(CustomWizard::Pro.subscribed?).to eq(true)
|
||||
expect(CustomWizard::Subscription.subscribed?).to eq(true)
|
||||
end
|
||||
end
|
|
@ -24,16 +24,16 @@ def get_wizard_fixture(path)
|
|||
).with_indifferent_access
|
||||
end
|
||||
|
||||
def authenticate_pro
|
||||
CustomWizard::ProAuthentication.any_instance.stubs(:active?).returns(true)
|
||||
def authenticate_subscription
|
||||
CustomWizard::Subscription::Authentication.any_instance.stubs(:active?).returns(true)
|
||||
end
|
||||
|
||||
def enable_subscription
|
||||
CustomWizard::Pro.any_instance.stubs(:subscribed?).returns(true)
|
||||
CustomWizard::Subscription.any_instance.stubs(:subscribed?).returns(true)
|
||||
end
|
||||
|
||||
def disable_pro
|
||||
CustomWizard::Pro.any_instance.stubs(:subscribed?).returns(false)
|
||||
def disable_subscription
|
||||
CustomWizard::Subscription.any_instance.stubs(:subscribed?).returns(false)
|
||||
end
|
||||
|
||||
def valid_subscription
|
||||
|
@ -52,7 +52,7 @@ def invalid_subscription
|
|||
end
|
||||
|
||||
def stub_subscription_request(status, subscription)
|
||||
authenticate_pro
|
||||
pro = CustomWizard::Pro.new
|
||||
stub_request(:get, "https://#{pro.server}/subscription-server/user-subscriptions/#{pro.subscription_type}/#{pro.client_name}").to_return(status: status, body: { subscriptions: [subscription] }.to_json)
|
||||
authenticate_subscription
|
||||
sub = CustomWizard::Subscription.new
|
||||
stub_request(:get, "https://#{sub.server}/subscription-server/user-subscriptions/#{sub.subscription_type}/#{sub.client_name}").to_return(status: status, body: { subscriptions: [subscription] }.to_json)
|
||||
end
|
||||
|
|
31
spec/requests/custom_wizard/admin/notice_controller_spec.rb
Normale Datei
31
spec/requests/custom_wizard/admin/notice_controller_spec.rb
Normale Datei
|
@ -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
|
|
@ -1,12 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
require_relative '../../../plugin_helper'
|
||||
|
||||
describe CustomWizard::AdminProController do
|
||||
describe CustomWizard::AdminSubscriptionController do
|
||||
fab!(:admin_user) { Fabricate(:user, admin: true) }
|
||||
|
||||
def generate_payload(request_id, user_id)
|
||||
uri = URI(@pro.authentication_url(user_id, request_id))
|
||||
keys = @pro.authentication.get_keys(request_id)
|
||||
uri = URI(@subscription.authentication_url(user_id, request_id))
|
||||
keys = @subscription.authentication.get_keys(request_id)
|
||||
raw_payload = {
|
||||
key: "12345",
|
||||
nonce: keys.nonce,
|
||||
|
@ -18,19 +18,19 @@ describe CustomWizard::AdminProController do
|
|||
end
|
||||
|
||||
before do
|
||||
@pro = CustomWizard::Pro.new
|
||||
@subscription = CustomWizard::Subscription.new
|
||||
sign_in(admin_user)
|
||||
end
|
||||
|
||||
it "#index" do
|
||||
get "/admin/wizards/pro.json"
|
||||
expect(response.parsed_body['server']).to eq(@pro.server)
|
||||
expect(response.parsed_body['authentication'].deep_symbolize_keys).to eq(CustomWizard::ProAuthenticationSerializer.new(@pro.authentication, root: false).as_json)
|
||||
expect(response.parsed_body['subscription'].deep_symbolize_keys).to eq(CustomWizard::ProSubscriptionSerializer.new(@pro.subscription, root: false).as_json)
|
||||
get "/admin/wizards/subscription.json"
|
||||
expect(response.parsed_body['server']).to eq(@subscription.server)
|
||||
expect(response.parsed_body['authentication'].deep_symbolize_keys).to eq(CustomWizard::Subscription::AuthenticationSerializer.new(@subscription.authentication, root: false).as_json)
|
||||
expect(response.parsed_body['subscription'].deep_symbolize_keys).to eq(CustomWizard::Subscription::SubscriptionSerializer.new(@subscription.subscription, root: false).as_json)
|
||||
end
|
||||
|
||||
it "#authorize" do
|
||||
get "/admin/wizards/pro/authorize"
|
||||
get "/admin/wizards/subscription/authorize"
|
||||
expect(response.status).to eq(302)
|
||||
expect(cookies[:user_api_request_id].present?).to eq(true)
|
||||
end
|
||||
|
@ -38,12 +38,12 @@ describe CustomWizard::AdminProController do
|
|||
it "#destroy_authentication" do
|
||||
request_id = SecureRandom.hex(32)
|
||||
payload = generate_payload(request_id, admin_user.id)
|
||||
@pro.authentication_response(request_id, payload)
|
||||
@subscription.authentication_response(request_id, payload)
|
||||
|
||||
delete "/admin/wizards/pro/authorize.json"
|
||||
delete "/admin/wizards/subscription/authorize.json"
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(CustomWizard::Pro.authorized?).to eq(false)
|
||||
expect(CustomWizard::Subscription.authorized?).to eq(false)
|
||||
end
|
||||
|
||||
context "subscription" do
|
||||
|
@ -54,18 +54,18 @@ describe CustomWizard::AdminProController do
|
|||
it "handles authentication response and the updates subscription" do
|
||||
request_id = cookies[:user_api_request_id] = SecureRandom.hex(32)
|
||||
payload = generate_payload(request_id, admin_user.id)
|
||||
get "/admin/wizards/pro/authorize/callback", params: { payload: payload }
|
||||
get "/admin/wizards/subscription/authorize/callback", params: { payload: payload }
|
||||
|
||||
expect(response).to redirect_to("/admin/wizards/pro")
|
||||
expect(CustomWizard::Pro.subscribed?).to eq(true)
|
||||
expect(response).to redirect_to("/admin/wizards/subscription")
|
||||
expect(CustomWizard::Subscription.subscribed?).to eq(true)
|
||||
end
|
||||
|
||||
it "updates the subscription" do
|
||||
authenticate_pro
|
||||
post "/admin/wizards/pro/subscription.json"
|
||||
authenticate_subscription
|
||||
post "/admin/wizards/subscription.json"
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(CustomWizard::Pro.subscribed?).to eq(true)
|
||||
expect(CustomWizard::Subscription.subscribed?).to eq(true)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -9,7 +9,7 @@ describe "custom field extensions" do
|
|||
let!(:user) { Fabricate(:user) }
|
||||
let!(:group) { Fabricate(:group, users: [user]) }
|
||||
let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") }
|
||||
let(:pro_custom_field_json) { get_wizard_fixture("custom_field/pro_custom_fields") }
|
||||
let(:subscription_custom_field_json) { get_wizard_fixture("custom_field/subscription_custom_fields") }
|
||||
|
||||
before do
|
||||
custom_field_json['custom_fields'].each do |field_json|
|
||||
|
@ -38,11 +38,11 @@ describe "custom field extensions" do
|
|||
expect(response.parsed_body['post_field_1']).to eq(7)
|
||||
end
|
||||
|
||||
context "with a pro subscription" do
|
||||
context "with a subscription" do
|
||||
before do
|
||||
enable_subscription
|
||||
|
||||
pro_custom_field_json['custom_fields'].each do |field_json|
|
||||
subscription_custom_field_json['custom_fields'].each do |field_json|
|
||||
custom_field = CustomWizard::CustomField.new(nil, field_json)
|
||||
custom_field.save
|
||||
end
|
||||
|
|
|
@ -119,7 +119,7 @@ describe CustomWizard::StepsController do
|
|||
expect(response.parsed_body['final']).to eq(true)
|
||||
end
|
||||
|
||||
context "pro" do
|
||||
context "subscription" do
|
||||
before do
|
||||
enable_subscription
|
||||
end
|
||||
|
@ -149,6 +149,38 @@ describe CustomWizard::StepsController do
|
|||
expect(response.parsed_body['wizard']['start']).to eq("step_3")
|
||||
end
|
||||
|
||||
it "returns the correct final step when the conditional final step and last step are the same" do
|
||||
new_template = wizard_template.dup
|
||||
new_template['steps'][0]['condition'] = user_condition_template['condition']
|
||||
new_template['steps'][2]['condition'] = wizard_field_condition_template['condition']
|
||||
CustomWizard::Template.save(new_template, skip_jobs: true)
|
||||
end
|
||||
|
||||
it "raises an error when user cant see the step due to conditions" do
|
||||
sign_in(user2)
|
||||
|
||||
new_wizard_template = wizard_template.dup
|
||||
new_wizard_template['steps'][0]['condition'] = user_condition_template['condition']
|
||||
CustomWizard::Template.save(new_wizard_template, skip_jobs: true)
|
||||
|
||||
put '/w/super-mega-fun-wizard/steps/step_1.json'
|
||||
expect(response.status).to eq(403)
|
||||
end
|
||||
|
||||
it "returns an updated wizard when condition doesnt pass" do
|
||||
new_template = wizard_template.dup
|
||||
new_template['steps'][1]['condition'] = wizard_field_condition_template['condition']
|
||||
CustomWizard::Template.save(new_template, skip_jobs: true)
|
||||
|
||||
put '/w/super-mega-fun-wizard/steps/step_1.json', params: {
|
||||
fields: {
|
||||
step_1_field_1: "Condition wont pass"
|
||||
}
|
||||
}
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body['wizard']['start']).to eq("step_3")
|
||||
end
|
||||
|
||||
it "returns the correct final step when the conditional final step and last step are the same" do
|
||||
new_template = wizard_template.dup
|
||||
new_template['steps'][0]['condition'] = user_condition_template['condition']
|
||||
|
|
22
spec/serializers/custom_wizard/notice_serializer_spec.rb
Normale Datei
22
spec/serializers/custom_wizard/notice_serializer_spec.rb
Normale Datei
|
@ -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
|
|
@ -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
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
require_relative '../../../plugin_helper'
|
||||
|
||||
describe CustomWizard::ProAuthenticationSerializer do
|
||||
describe CustomWizard::Subscription::AuthenticationSerializer do
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
|
||||
it 'should return pro authentication attributes' do
|
||||
auth = CustomWizard::ProAuthentication.new(OpenStruct.new(key: '1234', auth_at: Time.now, auth_by: user.id))
|
||||
it 'should return subscription authentication attributes' do
|
||||
auth = CustomWizard::Subscription::Authentication.new(OpenStruct.new(key: '1234', auth_at: Time.now, auth_by: user.id))
|
||||
serialized = described_class.new(auth, root: false).as_json
|
||||
|
||||
expect(serialized[:active]).to eq(true)
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
require_relative '../../../plugin_helper'
|
||||
|
||||
describe CustomWizard::ProSubscriptionSerializer do
|
||||
it 'should return pro subscription attributes' do
|
||||
sub = CustomWizard::ProSubscription.new(OpenStruct.new(type: 'community', updated_at: Time.now))
|
||||
describe CustomWizard::Subscription::SubscriptionSerializer do
|
||||
it 'should return subscription attributes' do
|
||||
sub = CustomWizard::Subscription::Subscription.new(OpenStruct.new(type: 'community', updated_at: Time.now))
|
||||
serialized = described_class.new(sub, root: false).as_json
|
||||
|
||||
expect(serialized[:active]).to eq(true)
|
14
spec/serializers/custom_wizard/subscription_serializer_spec.rb
Normale Datei
14
spec/serializers/custom_wizard/subscription_serializer_spec.rb
Normale Datei
|
@ -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
|
Laden …
In neuem Issue referenzieren