Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-11-22 09:20:29 +01:00
Commit
13304f5b6d
104 geänderte Dateien mit 2464 neuen und 1379 gelöschten Zeilen
|
@ -1,13 +1,29 @@
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||||
import { alias, equal, or } from "@ember/object/computed";
|
import { alias, equal, or } from "@ember/object/computed";
|
||||||
|
import { computed } from "@ember/object";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
|
||||||
const generateContent = function (array, type) {
|
const klasses = ["topic", "post", "group", "category"];
|
||||||
return array.map((key) => ({
|
const types = ["string", "boolean", "integer", "json"];
|
||||||
id: key,
|
const proTypes = {
|
||||||
name: I18n.t(`admin.wizard.custom_field.${type}.${key}`),
|
klass: ["group", "category"],
|
||||||
}));
|
type: ["json"],
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateContent = function (array, type, proSubscribed = false) {
|
||||||
|
return array.reduce((result, key) => {
|
||||||
|
let proArr = proTypes[type];
|
||||||
|
let pro = proArr && proArr.includes(key);
|
||||||
|
if (!pro || proSubscribed) {
|
||||||
|
result.push({
|
||||||
|
id: key,
|
||||||
|
name: I18n.t(`admin.wizard.custom_field.${type}.${key}`),
|
||||||
|
pro,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}, []);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
|
@ -16,14 +32,12 @@ export default Component.extend({
|
||||||
postSerializers: ["post"],
|
postSerializers: ["post"],
|
||||||
groupSerializers: ["basic_group"],
|
groupSerializers: ["basic_group"],
|
||||||
categorySerializers: ["basic_category"],
|
categorySerializers: ["basic_category"],
|
||||||
klassContent: generateContent(
|
klassContent: computed("proSubscribed", function () {
|
||||||
["topic", "post", "group", "category"],
|
return generateContent(klasses, "klass", this.proSubscribed);
|
||||||
"klass"
|
}),
|
||||||
),
|
typeContent: computed("proSubscribed", function () {
|
||||||
typeContent: generateContent(
|
return generateContent(types, "type", this.proSubscribed);
|
||||||
["string", "boolean", "integer", "json"],
|
}),
|
||||||
"type"
|
|
||||||
),
|
|
||||||
showInputs: or("field.new", "field.edit"),
|
showInputs: or("field.new", "field.edit"),
|
||||||
classNames: ["custom-field-input"],
|
classNames: ["custom-field-input"],
|
||||||
loading: or("saving", "destroying"),
|
loading: or("saving", "destroying"),
|
||||||
|
@ -40,7 +54,7 @@ export default Component.extend({
|
||||||
const serializers = this.get(`${klass}Serializers`);
|
const serializers = this.get(`${klass}Serializers`);
|
||||||
|
|
||||||
if (serializers) {
|
if (serializers) {
|
||||||
return generateContent(serializers, "serializers");
|
return generateContent(serializers, "serializers", this.proSubscribed);
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
|
||||||
import Component from "@ember/component";
|
|
||||||
|
|
||||||
export default Component.extend({
|
|
||||||
classNames: "wizard-advanced-toggle",
|
|
||||||
|
|
||||||
@discourseComputed("showAdvanced")
|
|
||||||
toggleClass(showAdvanced) {
|
|
||||||
let classes = "btn";
|
|
||||||
if (showAdvanced) {
|
|
||||||
classes += " btn-primary";
|
|
||||||
}
|
|
||||||
return classes;
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
toggleAdvanced() {
|
|
||||||
this.toggleProperty("showAdvanced");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
||||||
import { and, empty, equal, or } from "@ember/object/computed";
|
import wizardSchema from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-schema";
|
||||||
|
import { empty, equal, or } from "@ember/object/computed";
|
||||||
import { notificationLevels, selectKitContent } from "../lib/wizard";
|
import { notificationLevels, selectKitContent } from "../lib/wizard";
|
||||||
import { computed } from "@ember/object";
|
import { computed } from "@ember/object";
|
||||||
import wizardSchema from "../lib/wizard-schema";
|
|
||||||
import UndoChanges from "../mixins/undo-changes";
|
import UndoChanges from "../mixins/undo-changes";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
@ -25,8 +25,6 @@ export default Component.extend(UndoChanges, {
|
||||||
createGroup: equal("action.type", "create_group"),
|
createGroup: equal("action.type", "create_group"),
|
||||||
apiEmpty: empty("action.api"),
|
apiEmpty: empty("action.api"),
|
||||||
groupPropertyTypes: selectKitContent(["id", "name"]),
|
groupPropertyTypes: selectKitContent(["id", "name"]),
|
||||||
hasAdvanced: or("hasCustomFields", "routeTo"),
|
|
||||||
showAdvanced: and("hasAdvanced", "action.type"),
|
|
||||||
hasCustomFields: or(
|
hasCustomFields: or(
|
||||||
"basicTopicFields",
|
"basicTopicFields",
|
||||||
"updateProfile",
|
"updateProfile",
|
||||||
|
@ -36,12 +34,6 @@ export default Component.extend(UndoChanges, {
|
||||||
basicTopicFields: or("createTopic", "sendMessage", "openComposer"),
|
basicTopicFields: or("createTopic", "sendMessage", "openComposer"),
|
||||||
publicTopicFields: or("createTopic", "openComposer"),
|
publicTopicFields: or("createTopic", "openComposer"),
|
||||||
showPostAdvanced: or("createTopic", "sendMessage"),
|
showPostAdvanced: or("createTopic", "sendMessage"),
|
||||||
actionTypes: Object.keys(wizardSchema.action.types).map((type) => {
|
|
||||||
return {
|
|
||||||
id: type,
|
|
||||||
name: I18n.t(`admin.wizard.action.${type}.label`),
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
availableNotificationLevels: notificationLevels.map((type) => {
|
availableNotificationLevels: notificationLevels.map((type) => {
|
||||||
return {
|
return {
|
||||||
id: type,
|
id: type,
|
||||||
|
@ -101,4 +93,19 @@ export default Component.extend(UndoChanges, {
|
||||||
}
|
}
|
||||||
return apis.find((a) => a.name === api).endpoints;
|
return apis.find((a) => a.name === api).endpoints;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@discourseComputed("proSubscribed")
|
||||||
|
actionTypes(proSubscribed) {
|
||||||
|
return Object.keys(wizardSchema.action.types).reduce((result, type) => {
|
||||||
|
let pro = wizardSchema.action.proTypes.includes(type);
|
||||||
|
if (proSubscribed || !pro) {
|
||||||
|
result.push({
|
||||||
|
id: type,
|
||||||
|
name: I18n.t(`admin.wizard.action.${type}.label`),
|
||||||
|
pro,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}, []);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
||||||
import { alias, equal, or } from "@ember/object/computed";
|
import { equal, or } from "@ember/object/computed";
|
||||||
import { computed } from "@ember/object";
|
import { computed } from "@ember/object";
|
||||||
import { selectKitContent } from "../lib/wizard";
|
import { selectKitContent } from "../lib/wizard";
|
||||||
import UndoChanges from "../mixins/undo-changes";
|
import UndoChanges from "../mixins/undo-changes";
|
||||||
|
@ -27,7 +27,6 @@ export default Component.extend(UndoChanges, {
|
||||||
isTextType: or("isText", "isTextarea", "isComposer"),
|
isTextType: or("isText", "isTextarea", "isComposer"),
|
||||||
isComposerPreview: equal("field.type", "composer_preview"),
|
isComposerPreview: equal("field.type", "composer_preview"),
|
||||||
categoryPropertyTypes: selectKitContent(["id", "slug"]),
|
categoryPropertyTypes: selectKitContent(["id", "slug"]),
|
||||||
showAdvanced: alias("field.type"),
|
|
||||||
messageUrl: "https://thepavilion.io/t/2809",
|
messageUrl: "https://thepavilion.io/t/2809",
|
||||||
|
|
||||||
@discourseComputed("field.type")
|
@discourseComputed("field.type")
|
||||||
|
|
|
@ -6,6 +6,7 @@ import I18n from "I18n";
|
||||||
const icons = {
|
const icons = {
|
||||||
error: "times-circle",
|
error: "times-circle",
|
||||||
success: "check-circle",
|
success: "check-circle",
|
||||||
|
warn: "exclamation-circle",
|
||||||
info: "info-circle",
|
info: "info-circle",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
18
assets/javascripts/discourse/components/wizard-pro-selector.js.es6
Normale Datei
18
assets/javascripts/discourse/components/wizard-pro-selector.js.es6
Normale Datei
|
@ -0,0 +1,18 @@
|
||||||
|
import SingleSelectComponent from "select-kit/components/single-select";
|
||||||
|
|
||||||
|
export default SingleSelectComponent.extend({
|
||||||
|
classNames: ["combo-box", "wizard-pro-selector"],
|
||||||
|
|
||||||
|
selectKitOptions: {
|
||||||
|
autoFilterable: false,
|
||||||
|
filterable: false,
|
||||||
|
showFullTitle: true,
|
||||||
|
headerComponent: "wizard-pro-selector/wizard-pro-selector-header",
|
||||||
|
caretUpIcon: "caret-up",
|
||||||
|
caretDownIcon: "caret-down",
|
||||||
|
},
|
||||||
|
|
||||||
|
modifyComponentForRow() {
|
||||||
|
return "wizard-pro-selector/wizard-pro-selector-row";
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,17 @@
|
||||||
|
import SingleSelectHeaderComponent from "select-kit/components/select-kit/single-select-header";
|
||||||
|
import { computed } from "@ember/object";
|
||||||
|
import { reads } from "@ember/object/computed";
|
||||||
|
|
||||||
|
export default SingleSelectHeaderComponent.extend({
|
||||||
|
classNames: ["combo-box-header", "wizard-pro-selector-header"],
|
||||||
|
caretUpIcon: reads("selectKit.options.caretUpIcon"),
|
||||||
|
caretDownIcon: reads("selectKit.options.caretDownIcon"),
|
||||||
|
caretIcon: computed(
|
||||||
|
"selectKit.isExpanded",
|
||||||
|
"caretUpIcon",
|
||||||
|
"caretDownIcon",
|
||||||
|
function () {
|
||||||
|
return this.selectKit.isExpanded ? this.caretUpIcon : this.caretDownIcon;
|
||||||
|
}
|
||||||
|
),
|
||||||
|
});
|
|
@ -0,0 +1,3 @@
|
||||||
|
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
|
||||||
|
|
||||||
|
export default SelectKitRowComponent.extend();
|
|
@ -0,0 +1,53 @@
|
||||||
|
import Component from "@ember/component";
|
||||||
|
import CustomWizardPro from "../models/custom-wizard-pro";
|
||||||
|
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",
|
||||||
|
"subscription.active:active:inactive",
|
||||||
|
],
|
||||||
|
subscribed: notEmpty("subscription"),
|
||||||
|
|
||||||
|
@discourseComputed("subscription.type")
|
||||||
|
title(type) {
|
||||||
|
return type
|
||||||
|
? I18n.t(`admin.wizard.pro.subscription.title.${type}`)
|
||||||
|
: I18n.t("admin.wizard.pro.not_subscribed");
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("subscription.active")
|
||||||
|
stateClass(active) {
|
||||||
|
return active ? "active" : "inactive";
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("stateClass")
|
||||||
|
stateLabel(stateClass) {
|
||||||
|
return I18n.t(`admin.wizard.pro.subscription.status.${stateClass}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
update() {
|
||||||
|
this.set("updating", true);
|
||||||
|
CustomWizardPro.update_subscription()
|
||||||
|
.then((result) => {
|
||||||
|
if (result.success) {
|
||||||
|
this.setProperties({
|
||||||
|
updateIcon: "check",
|
||||||
|
subscription: result.subscription,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.set("updateIcon", "times");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.set("updating", false);
|
||||||
|
setTimeout(() => {
|
||||||
|
this.set("updateIcon", null);
|
||||||
|
}, 7000);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
|
@ -6,7 +6,8 @@ import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNames: ["realtime-validations"],
|
classNames: ["realtime-validations", "setting", "full", "pro"],
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
timeUnits() {
|
timeUnits() {
|
||||||
return ["days", "weeks", "months", "years"].map((unit) => {
|
return ["days", "weeks", "months", "years"].map((unit) => {
|
||||||
|
|
62
assets/javascripts/discourse/controllers/admin-wizards-pro.js.es6
Normale Datei
62
assets/javascripts/discourse/controllers/admin-wizards-pro.js.es6
Normale Datei
|
@ -0,0 +1,62 @@
|
||||||
|
import Controller from "@ember/controller";
|
||||||
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
import CustomWizardPro from "../models/custom-wizard-pro";
|
||||||
|
import { alias } from "@ember/object/computed";
|
||||||
|
|
||||||
|
export default Controller.extend({
|
||||||
|
messageUrl: "https://thepavilion.io/t/3652",
|
||||||
|
messageType: "info",
|
||||||
|
messageKey: null,
|
||||||
|
showSubscription: alias("model.authentication.active"),
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
const authentication = this.get("model.authentication");
|
||||||
|
const subscription = this.get("model.subscription");
|
||||||
|
const subscribed = subscription && subscription.active;
|
||||||
|
const authenticated = authentication && authentication.active;
|
||||||
|
|
||||||
|
if (!subscribed) {
|
||||||
|
this.set("messageKey", authenticated ? "not_subscribed" : "authorize");
|
||||||
|
} else {
|
||||||
|
this.set(
|
||||||
|
"messageKey",
|
||||||
|
!authenticated
|
||||||
|
? "subscription_expiring"
|
||||||
|
: subscribed
|
||||||
|
? "subscription_active"
|
||||||
|
: "subscription_inactive"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("model.server")
|
||||||
|
messageOpts(server) {
|
||||||
|
return { server };
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
unauthorize() {
|
||||||
|
this.set("unauthorizing", true);
|
||||||
|
|
||||||
|
CustomWizardPro.unauthorize()
|
||||||
|
.then((result) => {
|
||||||
|
if (result.success) {
|
||||||
|
this.setProperties({
|
||||||
|
messageKey: "unauthorized",
|
||||||
|
messageType: "warn",
|
||||||
|
"model.authentication": null,
|
||||||
|
"model.subscription": null,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setProperties({
|
||||||
|
messageKey: "unauthorize_failed",
|
||||||
|
messageType: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.set("unauthorizing", false);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
|
@ -77,7 +77,11 @@ export default Controller.extend({
|
||||||
wizard
|
wizard
|
||||||
.save(opts)
|
.save(opts)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.send("afterSave", result.wizard_id);
|
if (result.wizard_id) {
|
||||||
|
this.send("afterSave", result.wizard_id);
|
||||||
|
} else if (result.errors) {
|
||||||
|
this.set("error", result.errors.join(", "));
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((result) => {
|
.catch((result) => {
|
||||||
let errorType = "failed";
|
let errorType = "failed";
|
||||||
|
@ -114,10 +118,6 @@ export default Controller.extend({
|
||||||
controller.setup();
|
controller.setup();
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleAdvanced() {
|
|
||||||
this.toggleProperty("wizard.showAdvanced");
|
|
||||||
},
|
|
||||||
|
|
||||||
copyUrl() {
|
copyUrl() {
|
||||||
const $copyRange = $('<p id="copy-range"></p>');
|
const $copyRange = $('<p id="copy-range"></p>');
|
||||||
$copyRange.html(this.wizardUrl);
|
$copyRange.html(this.wizardUrl);
|
||||||
|
|
|
@ -43,12 +43,20 @@ export default {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
this.route("adminWizardsLogs", { path: "/logs", resetNamespace: true });
|
this.route("adminWizardsLogs", {
|
||||||
|
path: "/logs",
|
||||||
|
resetNamespace: true,
|
||||||
|
});
|
||||||
|
|
||||||
this.route("adminWizardsManager", {
|
this.route("adminWizardsManager", {
|
||||||
path: "/manager",
|
path: "/manager",
|
||||||
resetNamespace: true,
|
resetNamespace: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.route("adminWizardsPro", {
|
||||||
|
path: "/pro",
|
||||||
|
resetNamespace: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -97,11 +97,6 @@ function buildObjectArray(json, type) {
|
||||||
if (present(json)) {
|
if (present(json)) {
|
||||||
json.forEach((objJson, objectIndex) => {
|
json.forEach((objJson, objectIndex) => {
|
||||||
let object = buildObject(objJson, type, objectIndex);
|
let object = buildObject(objJson, type, objectIndex);
|
||||||
|
|
||||||
if (hasAdvancedProperties(object, type)) {
|
|
||||||
object.set("showAdvanced", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
array.pushObject(object);
|
array.pushObject(object);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -112,21 +107,11 @@ function buildObjectArray(json, type) {
|
||||||
function buildBasicProperties(json, type, props, objectIndex = null) {
|
function buildBasicProperties(json, type, props, objectIndex = null) {
|
||||||
listProperties(type).forEach((p) => {
|
listProperties(type).forEach((p) => {
|
||||||
props[p] = buildProperty(json, p, type, objectIndex);
|
props[p] = buildProperty(json, p, type, objectIndex);
|
||||||
|
|
||||||
if (hasAdvancedProperties(json, type)) {
|
|
||||||
props.showAdvanced = true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasAdvancedProperties(object, type) {
|
|
||||||
return Object.keys(object).some((p) => {
|
|
||||||
return wizardSchema[type].advanced.indexOf(p) > -1 && present(object[p]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// to be removed: necessary due to action array being moved from step to wizard
|
/// to be removed: necessary due to action array being moved from step to wizard
|
||||||
function actionPatch(json) {
|
function actionPatch(json) {
|
||||||
let actions = json.actions || [];
|
let actions = json.actions || [];
|
||||||
|
|
|
@ -18,7 +18,6 @@ const wizard = {
|
||||||
permitted: null,
|
permitted: null,
|
||||||
},
|
},
|
||||||
mapped: ["permitted"],
|
mapped: ["permitted"],
|
||||||
advanced: ["restart_on_revisit"],
|
|
||||||
required: ["id"],
|
required: ["id"],
|
||||||
dependent: {
|
dependent: {
|
||||||
after_time: "after_time_scheduled",
|
after_time: "after_time_scheduled",
|
||||||
|
@ -50,7 +49,6 @@ const step = {
|
||||||
force_final: false,
|
force_final: false,
|
||||||
},
|
},
|
||||||
mapped: ["required_data", "permitted_params", "condition", "index"],
|
mapped: ["required_data", "permitted_params", "condition", "index"],
|
||||||
advanced: ["required_data", "permitted_params", "condition", "index"],
|
|
||||||
required: ["id"],
|
required: ["id"],
|
||||||
dependent: {},
|
dependent: {},
|
||||||
objectArrays: {
|
objectArrays: {
|
||||||
|
@ -68,6 +66,7 @@ const field = {
|
||||||
label: null,
|
label: null,
|
||||||
image: null,
|
image: null,
|
||||||
description: null,
|
description: null,
|
||||||
|
property: null,
|
||||||
required: null,
|
required: null,
|
||||||
key: null,
|
key: null,
|
||||||
type: null,
|
type: null,
|
||||||
|
@ -75,7 +74,6 @@ const field = {
|
||||||
},
|
},
|
||||||
types: {},
|
types: {},
|
||||||
mapped: ["prefill", "content", "condition", "index"],
|
mapped: ["prefill", "content", "condition", "index"],
|
||||||
advanced: ["property", "key", "condition", "index"],
|
|
||||||
required: ["id", "type"],
|
required: ["id", "type"],
|
||||||
dependent: {},
|
dependent: {},
|
||||||
objectArrays: {},
|
objectArrays: {},
|
||||||
|
@ -196,14 +194,14 @@ const action = {
|
||||||
"visibility_level",
|
"visibility_level",
|
||||||
"members_visibility_level",
|
"members_visibility_level",
|
||||||
],
|
],
|
||||||
advanced: [
|
|
||||||
"code",
|
|
||||||
"custom_fields",
|
|
||||||
"skip_redirect",
|
|
||||||
"suppress_notifications",
|
|
||||||
"required",
|
|
||||||
],
|
|
||||||
required: ["id", "type"],
|
required: ["id", "type"],
|
||||||
|
proTypes: [
|
||||||
|
"send_message",
|
||||||
|
"add_to_group",
|
||||||
|
"create_category",
|
||||||
|
"create_group",
|
||||||
|
"send_to_api",
|
||||||
|
],
|
||||||
dependent: {},
|
dependent: {},
|
||||||
objectArrays: {},
|
objectArrays: {},
|
||||||
};
|
};
|
||||||
|
|
33
assets/javascripts/discourse/models/custom-wizard-pro.js.es6
Normale Datei
33
assets/javascripts/discourse/models/custom-wizard-pro.js.es6
Normale Datei
|
@ -0,0 +1,33 @@
|
||||||
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
import EmberObject from "@ember/object";
|
||||||
|
|
||||||
|
const CustomWizardPro = EmberObject.extend();
|
||||||
|
|
||||||
|
const basePath = "/admin/wizards/pro";
|
||||||
|
|
||||||
|
CustomWizardPro.reopenClass({
|
||||||
|
status() {
|
||||||
|
return ajax(basePath, {
|
||||||
|
type: "GET",
|
||||||
|
}).catch(popupAjaxError);
|
||||||
|
},
|
||||||
|
|
||||||
|
authorize() {
|
||||||
|
window.location.href = `${basePath}/authorize`;
|
||||||
|
},
|
||||||
|
|
||||||
|
unauthorize() {
|
||||||
|
return ajax(`${basePath}/authorize`, {
|
||||||
|
type: "DELETE",
|
||||||
|
}).catch(popupAjaxError);
|
||||||
|
},
|
||||||
|
|
||||||
|
update_subscription() {
|
||||||
|
return ajax(`${basePath}/subscription`, {
|
||||||
|
type: "POST",
|
||||||
|
}).catch(popupAjaxError);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default CustomWizardPro;
|
|
@ -8,7 +8,12 @@ export default DiscourseRoute.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
setupController(controller, model) {
|
setupController(controller, model) {
|
||||||
const customFields = A(model || []);
|
const customFields = A(model.custom_fields || []);
|
||||||
controller.set("customFields", customFields);
|
const proSubscribed = model.pro_subscribed;
|
||||||
|
|
||||||
|
controller.setProperties({
|
||||||
|
customFields,
|
||||||
|
proSubscribed,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
19
assets/javascripts/discourse/routes/admin-wizards-pro.js.es6
Normale Datei
19
assets/javascripts/discourse/routes/admin-wizards-pro.js.es6
Normale Datei
|
@ -0,0 +1,19 @@
|
||||||
|
import CustomWizardPro from "../models/custom-wizard-pro";
|
||||||
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
|
||||||
|
export default DiscourseRoute.extend({
|
||||||
|
model() {
|
||||||
|
return CustomWizardPro.status();
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController(controller, model) {
|
||||||
|
controller.set("model", model);
|
||||||
|
controller.setup();
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
authorize() {
|
||||||
|
CustomWizardPro.authorize();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
|
@ -39,6 +39,7 @@ export default DiscourseRoute.extend({
|
||||||
currentStep: wizard.steps[0],
|
currentStep: wizard.steps[0],
|
||||||
currentAction: wizard.actions[0],
|
currentAction: wizard.actions[0],
|
||||||
creating: model.create,
|
creating: model.create,
|
||||||
|
proSubscribed: parentModel.pro_subscribed,
|
||||||
};
|
};
|
||||||
|
|
||||||
controller.setProperties(props);
|
controller.setProperties(props);
|
||||||
|
|
|
@ -32,7 +32,8 @@
|
||||||
{{custom-field-input
|
{{custom-field-input
|
||||||
field=field
|
field=field
|
||||||
removeField=(action "removeField")
|
removeField=(action "removeField")
|
||||||
saveField=(action "saveField")}}
|
saveField=(action "saveField")
|
||||||
|
proSubscribed=proSubscribed}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
34
assets/javascripts/discourse/templates/admin-wizards-pro.hbs
Normale Datei
34
assets/javascripts/discourse/templates/admin-wizards-pro.hbs
Normale Datei
|
@ -0,0 +1,34 @@
|
||||||
|
<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>
|
|
@ -62,4 +62,4 @@
|
||||||
{{conditional-loading-spinner condition=loadingMore}}
|
{{conditional-loading-spinner condition=loadingMore}}
|
||||||
{{/load-more}}
|
{{/load-more}}
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -126,33 +126,25 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{wizard-advanced-toggle showAdvanced=wizard.showAdvanced}}
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
{{#if wizard.showAdvanced}}
|
<label>{{i18n "admin.wizard.save_submissions"}}</label>
|
||||||
<div class="advanced-settings">
|
|
||||||
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<label>{{i18n "admin.wizard.save_submissions"}}</label>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
|
||||||
{{input type="checkbox" checked=wizard.save_submissions}}
|
|
||||||
<span>{{i18n "admin.wizard.save_submissions_label"}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<label>{{i18n "admin.wizard.restart_on_revisit"}}</label>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
|
||||||
{{input type="checkbox" checked=wizard.restart_on_revisit}}
|
|
||||||
<span>{{i18n "admin.wizard.restart_on_revisit_label"}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
<div class="setting-value">
|
||||||
|
{{input type="checkbox" checked=wizard.save_submissions}}
|
||||||
|
<span>{{i18n "admin.wizard.save_submissions_label"}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n "admin.wizard.restart_on_revisit"}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input type="checkbox" checked=wizard.restart_on_revisit}}
|
||||||
|
<span>{{i18n "admin.wizard.restart_on_revisit_label"}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{wizard-links
|
{{wizard-links
|
||||||
|
@ -166,7 +158,8 @@
|
||||||
wizard=wizard
|
wizard=wizard
|
||||||
currentField=currentField
|
currentField=currentField
|
||||||
wizardFields=wizardFields
|
wizardFields=wizardFields
|
||||||
fieldTypes=fieldTypes}}
|
fieldTypes=fieldTypes
|
||||||
|
proSubscribed=proSubscribed}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{wizard-links
|
{{wizard-links
|
||||||
|
@ -182,7 +175,8 @@
|
||||||
wizard=wizard
|
wizard=wizard
|
||||||
apis=apis
|
apis=apis
|
||||||
removeAction="removeAction"
|
removeAction="removeAction"
|
||||||
wizardFields=wizardFields}}
|
wizardFields=wizardFields
|
||||||
|
proSubscribed=proSubscribed}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
<div class="admin-wizard-buttons">
|
<div class="admin-wizard-buttons">
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{nav-item route="adminWizardsLogs" label="admin.wizard.log.nav_label"}}
|
{{nav-item route="adminWizardsLogs" label="admin.wizard.log.nav_label"}}
|
||||||
{{nav-item route="adminWizardsManager" label="admin.wizard.manager.nav_label"}}
|
{{nav-item route="adminWizardsManager" label="admin.wizard.manager.nav_label"}}
|
||||||
|
{{nav-item route="adminWizardsPro" label="admin.wizard.pro.nav_label"}}
|
||||||
|
|
||||||
<div class="admin-actions">
|
<div class="admin-actions">
|
||||||
<a target="_blank" class="btn btn-pavilion-pro" rel="noreferrer noopener" href="https://thepavilion.io/w/support" title={{i18n "admin.wizard.pro_support_button.title"}}>{{d-icon "far-life-ring"}}{{i18n "admin.wizard.pro_support_button.label"}}</a>
|
<a target="_blank" class="btn btn-pavilion-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>
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
{{#if showInputs}}
|
{{#if showInputs}}
|
||||||
<td>
|
<td>
|
||||||
{{combo-box
|
{{wizard-pro-selector
|
||||||
value=field.klass
|
value=field.klass
|
||||||
content=klassContent
|
content=klassContent
|
||||||
none="admin.wizard.custom_field.klass.select"
|
none="admin.wizard.custom_field.klass.select"
|
||||||
onChange=(action (mut field.klass))}}
|
onChange=(action (mut field.klass))}}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{combo-box
|
{{wizard-pro-selector
|
||||||
value=field.type
|
value=field.type
|
||||||
content=typeContent
|
content=typeContent
|
||||||
none="admin.wizard.custom_field.type.select"
|
none="admin.wizard.custom_field.type.select"
|
||||||
|
|
|
@ -160,4 +160,4 @@
|
||||||
<span class="submission-date" title={{value.value}}>
|
<span class="submission-date" title={{value.value}}>
|
||||||
{{d-icon "clock"}}{{format-date value format="tiny"}}
|
{{d-icon "clock"}}{{format-date value format="tiny"}}
|
||||||
</span>
|
</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
{{d-button
|
|
||||||
action="toggleAdvanced"
|
|
||||||
label="admin.wizard.advanced"
|
|
||||||
class=toggleClass}}
|
|
|
@ -12,13 +12,14 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{combo-box
|
{{wizard-pro-selector
|
||||||
value=action.type
|
value=action.type
|
||||||
content=actionTypes
|
content=actionTypes
|
||||||
onChange=(action "changeType")
|
onChange=(action "changeType")
|
||||||
options=(hash
|
options=(hash
|
||||||
none="admin.wizard.select_type"
|
none="admin.wizard.select_type"
|
||||||
)}}
|
)
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -714,99 +715,90 @@
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if showAdvanced}}
|
{{#if hasCustomFields}}
|
||||||
{{wizard-advanced-toggle showAdvanced=action.showAdvanced}}
|
<div class="setting full field-mapper-setting">
|
||||||
|
<div class="setting-label">
|
||||||
{{#if action.showAdvanced}}
|
<label>{{i18n "admin.wizard.action.custom_fields.label"}}</label>
|
||||||
<div class="advanced-settings">
|
|
||||||
|
|
||||||
{{#if hasCustomFields}}
|
|
||||||
<div class="setting full field-mapper-setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<label>{{i18n "admin.wizard.action.custom_fields.label"}}</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting-value">
|
|
||||||
{{wizard-mapper
|
|
||||||
inputs=action.custom_fields
|
|
||||||
property="custom_fields"
|
|
||||||
onUpdate=(action "mappedFieldUpdated")
|
|
||||||
options=(hash
|
|
||||||
inputTypes="association"
|
|
||||||
customFieldSelection="key"
|
|
||||||
wizardFieldSelection="value"
|
|
||||||
wizardActionSelection="value"
|
|
||||||
userFieldSelection="value"
|
|
||||||
keyPlaceholder="admin.wizard.action.custom_fields.key"
|
|
||||||
context=customFieldsContext
|
|
||||||
)}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if sendMessage}}
|
|
||||||
<div class="setting full field-mapper-setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<label>{{i18n "admin.wizard.required"}}</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting-value">
|
|
||||||
{{wizard-mapper
|
|
||||||
inputs=action.required
|
|
||||||
property="required"
|
|
||||||
onUpdate=(action "mappedFieldUpdated")
|
|
||||||
options=(hash
|
|
||||||
textSelection="value"
|
|
||||||
wizardFieldSelection=true
|
|
||||||
userFieldSelection=true
|
|
||||||
groupSelection=true
|
|
||||||
context="action"
|
|
||||||
)}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if showPostAdvanced}}
|
|
||||||
<div class="setting full">
|
|
||||||
<div class="setting-label">
|
|
||||||
<label>{{i18n "admin.wizard.action.skip_redirect.label"}}</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting-value">
|
|
||||||
{{input type="checkbox" checked=action.skip_redirect}}
|
|
||||||
|
|
||||||
<span>
|
|
||||||
{{i18n "admin.wizard.action.skip_redirect.description" type="topic"}}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting full">
|
|
||||||
<div class="setting-label">
|
|
||||||
<label>{{i18n "admin.wizard.action.suppress_notifications.label"}}</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting-value">
|
|
||||||
{{input type="checkbox" checked=action.suppress_notifications}}
|
|
||||||
|
|
||||||
<span>
|
|
||||||
{{i18n "admin.wizard.action.suppress_notifications.description" type="topic"}}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if routeTo}}
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<label>{{i18n "admin.wizard.action.route_to.code"}}</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting-value">
|
|
||||||
{{input value=action.code}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
|
||||||
|
<div class="setting-value">
|
||||||
|
{{wizard-mapper
|
||||||
|
inputs=action.custom_fields
|
||||||
|
property="custom_fields"
|
||||||
|
onUpdate=(action "mappedFieldUpdated")
|
||||||
|
options=(hash
|
||||||
|
inputTypes="association"
|
||||||
|
customFieldSelection="key"
|
||||||
|
wizardFieldSelection="value"
|
||||||
|
wizardActionSelection="value"
|
||||||
|
userFieldSelection="value"
|
||||||
|
keyPlaceholder="admin.wizard.action.custom_fields.key"
|
||||||
|
context=customFieldsContext
|
||||||
|
)}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if sendMessage}}
|
||||||
|
<div class="setting full field-mapper-setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n "admin.wizard.required"}}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-value">
|
||||||
|
{{wizard-mapper
|
||||||
|
inputs=action.required
|
||||||
|
property="required"
|
||||||
|
onUpdate=(action "mappedFieldUpdated")
|
||||||
|
options=(hash
|
||||||
|
textSelection="value"
|
||||||
|
wizardFieldSelection=true
|
||||||
|
userFieldSelection=true
|
||||||
|
groupSelection=true
|
||||||
|
context="action"
|
||||||
|
)}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if showPostAdvanced}}
|
||||||
|
<div class="setting full">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n "admin.wizard.action.skip_redirect.label"}}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input type="checkbox" checked=action.skip_redirect}}
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{{i18n "admin.wizard.action.skip_redirect.description" type="topic"}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting full">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n "admin.wizard.action.suppress_notifications.label"}}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input type="checkbox" checked=action.suppress_notifications}}
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{{i18n "admin.wizard.action.suppress_notifications.description" type="topic"}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if routeTo}}
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n "admin.wizard.action.route_to.code"}}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input value=action.code}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -207,70 +207,66 @@
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if showAdvanced}}
|
{{#if proSubscribed}}
|
||||||
{{wizard-advanced-toggle showAdvanced=field.showAdvanced}}
|
<div class="setting full field-mapper-setting pro">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n "admin.wizard.condition"}}</label>
|
||||||
|
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{#if field.showAdvanced}}
|
<div class="setting-value">
|
||||||
<div class="advanced-settings">
|
{{wizard-mapper
|
||||||
|
inputs=field.condition
|
||||||
|
options=fieldConditionOptions}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting full field-mapper-setting pro">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n "admin.wizard.index"}}</label>
|
||||||
|
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="setting full field-mapper-setting">
|
<div class="setting-value">
|
||||||
<div class="setting-label">
|
{{wizard-mapper
|
||||||
<label>{{i18n "admin.wizard.condition"}}</label>
|
inputs=field.index
|
||||||
</div>
|
options=fieldIndexOptions}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
{{#if isCategory}}
|
||||||
{{wizard-mapper
|
<div class="setting pro">
|
||||||
inputs=field.condition
|
<div class="setting-label">
|
||||||
options=fieldConditionOptions}}
|
<label>{{i18n "admin.wizard.field.property"}}</label>
|
||||||
</div>
|
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting full field-mapper-setting">
|
<div class="setting-value">
|
||||||
<div class="setting-label">
|
{{combo-box
|
||||||
<label>{{i18n "admin.wizard.index"}}</label>
|
value=field.property
|
||||||
</div>
|
content=categoryPropertyTypes
|
||||||
|
onChange=(action (mut field.property))
|
||||||
<div class="setting-value">
|
options=(hash
|
||||||
{{wizard-mapper
|
none="admin.wizard.selector.placeholder.property"
|
||||||
inputs=field.index
|
)}}
|
||||||
options=fieldIndexOptions}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if isCategory}}
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<label>{{i18n "admin.wizard.field.property"}}</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting-value">
|
|
||||||
{{combo-box
|
|
||||||
value=field.property
|
|
||||||
content=categoryPropertyTypes
|
|
||||||
onChange=(action (mut field.property))
|
|
||||||
options=(hash
|
|
||||||
none="admin.wizard.selector.placeholder.property"
|
|
||||||
)}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<label>{{i18n "admin.wizard.translation"}}</label>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value medium">
|
|
||||||
{{input
|
|
||||||
name="key"
|
|
||||||
value=field.key
|
|
||||||
class="medium"
|
|
||||||
placeholderKey="admin.wizard.translation_placeholder"}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if validations}}
|
|
||||||
{{wizard-realtime-validations field=field validations=validations}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="setting pro">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n "admin.wizard.translation"}}</label>
|
||||||
|
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input
|
||||||
|
name="key"
|
||||||
|
value=field.key
|
||||||
|
placeholderKey="admin.wizard.translation_placeholder"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if validations}}
|
||||||
|
{{wizard-realtime-validations field=field validations=validations}}
|
||||||
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -33,85 +33,84 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{wizard-advanced-toggle showAdvanced=step.showAdvanced}}
|
{{#if proSubscribed}}
|
||||||
|
<div class="setting full field-mapper-setting pro">
|
||||||
{{#if step.showAdvanced}}
|
<div class="setting-label">
|
||||||
<div class="advanced-settings">
|
<label>{{i18n "admin.wizard.condition"}}</label>
|
||||||
|
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||||
<div class="setting full field-mapper-setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<label>{{i18n "admin.wizard.condition"}}</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting-value">
|
|
||||||
{{wizard-mapper
|
|
||||||
inputs=step.condition
|
|
||||||
options=stepConditionOptions}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting full">
|
<div class="setting-value">
|
||||||
<div class="setting-label"></div>
|
{{wizard-mapper
|
||||||
<div class="setting-value force-final">
|
inputs=step.condition
|
||||||
<h4>{{i18n "admin.wizard.step.force_final.label"}}</h4>
|
options=stepConditionOptions}}
|
||||||
{{input type="checkbox" checked=step.force_final}}
|
|
||||||
<span>{{i18n "admin.wizard.step.force_final.description"}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="setting full field-mapper-setting">
|
<div class="setting full">
|
||||||
<div class="setting-label">
|
<div class="setting-label"></div>
|
||||||
<label>{{i18n "admin.wizard.step.required_data.label"}}</label>
|
<div class="setting-value force-final">
|
||||||
</div>
|
<h4>{{i18n "admin.wizard.step.force_final.label"}}</h4>
|
||||||
<div class="setting-value">
|
{{input type="checkbox" checked=step.force_final}}
|
||||||
{{wizard-mapper
|
<span>{{i18n "admin.wizard.step.force_final.description"}}</span>
|
||||||
inputs=step.required_data
|
</div>
|
||||||
options=(hash
|
</div>
|
||||||
inputTypes="validation"
|
|
||||||
inputConnector="and"
|
<div class="setting full field-mapper-setting pro">
|
||||||
wizardFieldSelection="value"
|
<div class="setting-label">
|
||||||
userFieldSelection="value"
|
<label>{{i18n "admin.wizard.step.required_data.label"}}</label>
|
||||||
keyPlaceholder="admin.wizard.submission_key"
|
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||||
context="step"
|
</div>
|
||||||
)}}
|
<div class="setting-value">
|
||||||
{{#if step.required_data}}
|
{{wizard-mapper
|
||||||
<div class="required-data-message">
|
inputs=step.required_data
|
||||||
<div class="label">
|
options=(hash
|
||||||
{{i18n "admin.wizard.step.required_data.not_permitted_message"}}
|
inputTypes="validation"
|
||||||
</div>
|
inputConnector="and"
|
||||||
{{input value=step.required_data_message}}
|
wizardFieldSelection="value"
|
||||||
|
userFieldSelection="value"
|
||||||
|
keyPlaceholder="admin.wizard.submission_key"
|
||||||
|
context="step"
|
||||||
|
)}}
|
||||||
|
{{#if step.required_data}}
|
||||||
|
<div class="required-data-message">
|
||||||
|
<div class="label">
|
||||||
|
{{i18n "admin.wizard.step.required_data.not_permitted_message"}}
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{input value=step.required_data_message}}
|
||||||
</div>
|
</div>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="setting full field-mapper-setting">
|
<div class="setting full field-mapper-setting pro">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<label>{{i18n "admin.wizard.step.permitted_params.label"}}</label>
|
<label>{{i18n "admin.wizard.step.permitted_params.label"}}</label>
|
||||||
</div>
|
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||||
<div class="setting-value">
|
|
||||||
{{wizard-mapper
|
|
||||||
inputs=step.permitted_params
|
|
||||||
options=(hash
|
|
||||||
pairConnector="set"
|
|
||||||
inputTypes="association"
|
|
||||||
keyPlaceholder="admin.wizard.param_key"
|
|
||||||
valuePlaceholder="admin.wizard.submission_key"
|
|
||||||
context="step"
|
|
||||||
)}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
{{wizard-mapper
|
||||||
|
inputs=step.permitted_params
|
||||||
|
options=(hash
|
||||||
|
pairConnector="set"
|
||||||
|
inputTypes="association"
|
||||||
|
keyPlaceholder="admin.wizard.param_key"
|
||||||
|
valuePlaceholder="admin.wizard.submission_key"
|
||||||
|
context="step"
|
||||||
|
)}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="setting">
|
<div class="setting pro">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<label>{{i18n "admin.wizard.translation"}}</label>
|
<label>{{i18n "admin.wizard.translation"}}</label>
|
||||||
</div>
|
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||||
<div class="setting-value">
|
</div>
|
||||||
{{input
|
<div class="setting-value">
|
||||||
name="key"
|
{{input
|
||||||
value=step.key
|
name="key"
|
||||||
placeholderKey="admin.wizard.translation_placeholder"}}
|
value=step.key
|
||||||
</div>
|
placeholderKey="admin.wizard.translation_placeholder"}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
@ -129,5 +128,6 @@
|
||||||
currentFieldId=currentField.id
|
currentFieldId=currentField.id
|
||||||
fieldTypes=fieldTypes
|
fieldTypes=fieldTypes
|
||||||
removeField="removeField"
|
removeField="removeField"
|
||||||
wizardFields=wizardFields}}
|
wizardFields=wizardFields
|
||||||
|
proSubscribed=proSubscribed}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<div class="select-kit-header-wrapper">
|
||||||
|
|
||||||
|
{{component selectKit.options.selectedNameComponent
|
||||||
|
tabindex=tabindex
|
||||||
|
item=selectedContent
|
||||||
|
selectKit=selectKit
|
||||||
|
shouldDisplayClearableButton=shouldDisplayClearableButton
|
||||||
|
}}
|
||||||
|
|
||||||
|
{{#if selectedContent.pro}}
|
||||||
|
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{d-icon caretIcon class="caret-icon"}}
|
||||||
|
</div>
|
|
@ -0,0 +1,15 @@
|
||||||
|
{{#if icons}}
|
||||||
|
<div class="icons">
|
||||||
|
<span class="selection-indicator"></span>
|
||||||
|
{{#each icons as |icon|}}
|
||||||
|
{{d-icon icon translatedtitle=(dasherize title)}}
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="texts">
|
||||||
|
<span class="name">{{html-safe label}}</span>
|
||||||
|
{{#if item.pro}}
|
||||||
|
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
|
@ -0,0 +1,31 @@
|
||||||
|
<div class="title-container">
|
||||||
|
<h3 class="subscription-title">{{title}}</h3>
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
<span>
|
||||||
|
{{#if updating}}
|
||||||
|
{{loading-spinner size="small"}}
|
||||||
|
{{else if updateIcon}}
|
||||||
|
{{d-icon updateIcon}}
|
||||||
|
{{/if}}
|
||||||
|
</span>
|
||||||
|
{{d-button
|
||||||
|
icon="sync"
|
||||||
|
action=(action "update")
|
||||||
|
disabled=updating
|
||||||
|
title="admin.wizard.pro.subscription.update"
|
||||||
|
label="admin.wizard.pro.subscription.update"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if subscribed}}
|
||||||
|
<div class="detail-container">
|
||||||
|
<div class="subscription-state {{stateClass}}" title={{stateLabel}}>{{stateLabel}}</div>
|
||||||
|
|
||||||
|
{{#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"}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
|
@ -1,50 +1,54 @@
|
||||||
<h3>{{i18n "admin.wizard.field.validations.header"}}</h3>
|
<div class="setting-label">
|
||||||
|
<label>{{i18n "admin.wizard.field.validations.header"}}</label>
|
||||||
<ul>
|
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||||
{{#each-in field.validations as |type props|}}
|
</div>
|
||||||
<li>
|
<div class="setting-value full">
|
||||||
<span class="setting-title">
|
<ul>
|
||||||
<h4>{{i18n (concat "admin.wizard.field.validations." type)}}</h4>
|
{{#each-in field.validations as |type props|}}
|
||||||
{{input type="checkbox" checked=props.status}}
|
<li>
|
||||||
{{i18n "admin.wizard.field.validations.enabled"}}
|
<span class="setting-title">
|
||||||
</span>
|
<h4>{{i18n (concat "admin.wizard.field.validations." type)}}</h4>
|
||||||
<div class="validation-container">
|
{{input type="checkbox" checked=props.status}}
|
||||||
<div class="validation-section">
|
{{i18n "admin.wizard.field.validations.enabled"}}
|
||||||
<div class="setting-label">
|
</span>
|
||||||
<label>{{i18n "admin.wizard.field.validations.categories"}}</label>
|
<div class="validation-container">
|
||||||
|
<div class="validation-section">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n "admin.wizard.field.validations.categories"}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
{{category-selector
|
||||||
|
categories=(get this (concat "validationBuffer." type ".categories"))
|
||||||
|
onChange=(action "updateValidationCategories" type props)
|
||||||
|
class="wizard"}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="validation-section">
|
||||||
{{category-selector
|
<div class="setting-label">
|
||||||
categories=(get this (concat "validationBuffer." type ".categories"))
|
<label>{{i18n "admin.wizard.field.validations.max_topic_age"}}</label>
|
||||||
onChange=(action "updateValidationCategories" type props)
|
</div>
|
||||||
class="wizard"}}
|
<div class="setting-value">
|
||||||
|
{{input type="number" class="time-n-value" value=props.time_n_value}}
|
||||||
|
{{combo-box
|
||||||
|
value=(readonly props.time_unit)
|
||||||
|
content=timeUnits
|
||||||
|
class="time-unit-selector"
|
||||||
|
onChange=(action (mut props.time_unit))}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="validation-section">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n "admin.wizard.field.validations.position"}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
{{radio-button name=(concat type field.id) value="above" selection=props.position}}
|
||||||
|
<span>{{i18n "admin.wizard.field.validations.above"}}</span>
|
||||||
|
{{radio-button name=(concat type field.id) value="below" selection=props.position}}
|
||||||
|
<span>{{i18n "admin.wizard.field.validations.below"}}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="validation-section">
|
</li>
|
||||||
<div class="setting-label">
|
{{/each-in}}
|
||||||
<label>{{i18n "admin.wizard.field.validations.max_topic_age"}}</label>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
|
||||||
{{input type="number" class="time-n-value" value=props.time_n_value}}
|
|
||||||
{{combo-box
|
|
||||||
value=(readonly props.time_unit)
|
|
||||||
content=timeUnits
|
|
||||||
class="time-unit-selector"
|
|
||||||
onChange=(action (mut props.time_unit))}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="validation-section">
|
|
||||||
<div class="setting-label">
|
|
||||||
<label>{{i18n "admin.wizard.field.validations.position"}}</label>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
|
||||||
{{radio-button name=(concat type field.id) value="above" selection=props.position}}
|
|
||||||
{{i18n "admin.wizard.field.validations.above"}}
|
|
||||||
{{radio-button name=(concat type field.id) value="below" selection=props.position}}
|
|
||||||
{{i18n "admin.wizard.field.validations.below"}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
{{/each-in}}
|
|
||||||
</ul>
|
|
||||||
|
|
|
@ -29,4 +29,4 @@
|
||||||
label="directory.edit_columns.reset_to_default"
|
label="directory.edit_columns.reset_to_default"
|
||||||
action=(action "resetToDefault")
|
action=(action "resetToDefault")
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 10px;
|
||||||
|
|
||||||
& + .wizard-message + div {
|
& + .wizard-message + div {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
|
@ -294,7 +294,7 @@
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
}
|
}
|
||||||
|
|
||||||
span {
|
> span {
|
||||||
font-size: 0.929em;
|
font-size: 0.929em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,6 +423,17 @@
|
||||||
.setting-gutter {
|
.setting-gutter {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.pro {
|
||||||
|
.setting-label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.advanced-settings {
|
.advanced-settings {
|
||||||
|
@ -729,27 +740,59 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.realtime-validations > ul {
|
.admin-wizard-container.settings .realtime-validations .setting-value > ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
> li {
|
> li {
|
||||||
background-color: var(--primary-low);
|
background-color: var(--primary-low);
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
margin: 0 0 1em 0;
|
margin: 0 0 1em 0;
|
||||||
|
|
||||||
input {
|
.setting-title {
|
||||||
margin-bottom: 0;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
margin: 0 15px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"] {
|
||||||
|
margin: 0 5px 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-label {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-value {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.input .select-kit,
|
||||||
|
> .select-kit {
|
||||||
|
max-width: unset !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
> span {
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.validation-container {
|
.validation-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
padding: 1em 0;
|
padding: 1em 0;
|
||||||
|
|
||||||
.validation-section {
|
.validation-section {
|
||||||
width: 250px;
|
min-width: 250px;
|
||||||
|
margin: 0.5em 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -767,6 +810,82 @@
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pro-label {
|
||||||
|
color: var(--tertiary);
|
||||||
|
font-size: 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-wizards-pro {
|
||||||
|
.admin-wizard-controls {
|
||||||
|
h3,
|
||||||
|
label {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
padding: 0.4em 0.5em;
|
||||||
|
margin-left: 0.75em;
|
||||||
|
background-color: var(--success);
|
||||||
|
color: var(--secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.loading-container {
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-wizard-pro-subscription {
|
||||||
|
.title-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons > span {
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 1em;
|
||||||
|
background-color: var(--primary-very-low);
|
||||||
|
|
||||||
|
.subscription-state {
|
||||||
|
padding: 0.25em 0.5em;
|
||||||
|
margin-right: 0.75em;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: var(--success);
|
||||||
|
color: var(--secondary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-pro-selector.select-kit.single-select {
|
||||||
|
.select-kit-row .texts {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pro-label {
|
||||||
|
margin-left: 0.75em;
|
||||||
|
padding-top: 0.25em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.btn.btn-pavilion-pro {
|
.btn.btn-pavilion-pro {
|
||||||
background: var(--pavilion-primary);
|
background: var(--pavilion-primary);
|
||||||
color: var(--pavilion-secondary);
|
color: var(--pavilion-secondary);
|
||||||
|
|
|
@ -58,10 +58,11 @@ en:
|
||||||
select_type: "Select a type"
|
select_type: "Select a type"
|
||||||
condition: "Condition"
|
condition: "Condition"
|
||||||
index: "Index"
|
index: "Index"
|
||||||
|
|
||||||
pro_support_button:
|
pro_support_button:
|
||||||
title: "Request Pro Support"
|
title: "Request Pro Support"
|
||||||
label: "Pro Support"
|
label: "Pro Support"
|
||||||
|
|
||||||
message:
|
message:
|
||||||
wizard:
|
wizard:
|
||||||
select: "Select a wizard, or create a new one"
|
select: "Select a wizard, or create a new one"
|
||||||
|
@ -89,11 +90,19 @@ en:
|
||||||
no_file: Please choose a file to import
|
no_file: Please choose a file to import
|
||||||
file_size_error: The file size must be 512kb or less
|
file_size_error: The file size must be 512kb or less
|
||||||
file_format_error: The file must be a .json file
|
file_format_error: The file must be a .json file
|
||||||
server_error: "Error: {{message}}"
|
|
||||||
importing: Importing wizards...
|
importing: Importing wizards...
|
||||||
destroying: Destroying wizards...
|
destroying: Destroying wizards...
|
||||||
import_complete: Import complete
|
import_complete: Import complete
|
||||||
destroy_complete: Destruction 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_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>."
|
||||||
|
unauthorized: "You're unauthorized. If you have a subscription, it will become inactive in the next 48 hours."
|
||||||
|
unauthorize_failed: Failed to unauthorize.
|
||||||
submissions:
|
submissions:
|
||||||
select: "Select a wizard to see its submissions"
|
select: "Select a wizard to see its submissions"
|
||||||
viewing: "You're viewing the submissions of the %{wizardName}. Click 'Download' on the right to download them."
|
viewing: "You're viewing the submissions of the %{wizardName}. Click 'Download' on the right to download them."
|
||||||
|
@ -102,7 +111,6 @@ en:
|
||||||
viewing: "View recent logs for wizards on the forum"
|
viewing: "View recent logs for wizards on the forum"
|
||||||
documentation: "Check out the logs documentation"
|
documentation: "Check out the logs documentation"
|
||||||
|
|
||||||
|
|
||||||
editor:
|
editor:
|
||||||
show: "Show"
|
show: "Show"
|
||||||
hide: "Hide"
|
hide: "Hide"
|
||||||
|
@ -182,9 +190,9 @@ en:
|
||||||
min_length_placeholder: "Minimum length in characters"
|
min_length_placeholder: "Minimum length in characters"
|
||||||
max_length: "Max Length"
|
max_length: "Max Length"
|
||||||
max_length_placeholder: "Maximum length in characters"
|
max_length_placeholder: "Maximum length in characters"
|
||||||
char_counter: "Character Counter"
|
char_counter: "Counter"
|
||||||
char_counter_placeholder: "Display Character Counter"
|
char_counter_placeholder: "Display Character Counter"
|
||||||
field_placeholder: "Field Placeholder"
|
field_placeholder: "Placeholder"
|
||||||
file_types: "File Types"
|
file_types: "File Types"
|
||||||
preview_template: "Preview Template"
|
preview_template: "Preview Template"
|
||||||
limit: "Limit"
|
limit: "Limit"
|
||||||
|
@ -195,7 +203,7 @@ en:
|
||||||
label: "Format"
|
label: "Format"
|
||||||
instructions: "<a href='https://momentjs.com/docs/#/displaying/format/' target='_blank'>Moment.js format</a>"
|
instructions: "<a href='https://momentjs.com/docs/#/displaying/format/' target='_blank'>Moment.js format</a>"
|
||||||
validations:
|
validations:
|
||||||
header: "Realtime Validations"
|
header: "Validations"
|
||||||
enabled: "Enabled"
|
enabled: "Enabled"
|
||||||
similar_topics: "Similar Topics"
|
similar_topics: "Similar Topics"
|
||||||
position: "Position"
|
position: "Position"
|
||||||
|
@ -441,7 +449,25 @@ en:
|
||||||
imported: imported
|
imported: imported
|
||||||
upload: Select wizards.json
|
upload: Select wizards.json
|
||||||
destroy: Destroy
|
destroy: Destroy
|
||||||
destroyed: destroyed
|
destroyed: destroyed
|
||||||
|
|
||||||
|
pro:
|
||||||
|
nav_label: PRO
|
||||||
|
label: PRO
|
||||||
|
title: Custom Wizard PRO
|
||||||
|
authorize: Authorize
|
||||||
|
authorized: Authorized
|
||||||
|
unauthorize: cancel
|
||||||
|
not_subscribed: You're not currently subscribed
|
||||||
|
subscription:
|
||||||
|
title:
|
||||||
|
community: Community Subscription
|
||||||
|
business: Business Subscription
|
||||||
|
status:
|
||||||
|
active: Active
|
||||||
|
inactive: Inactive
|
||||||
|
update: Update
|
||||||
|
last_updated: Last updated
|
||||||
|
|
||||||
wizard_js:
|
wizard_js:
|
||||||
group:
|
group:
|
||||||
|
|
|
@ -17,6 +17,7 @@ en:
|
||||||
name_too_short: "'%{name}' is too short for a custom field name (min length is #{min_length})"
|
name_too_short: "'%{name}' is too short for a custom field name (min length is #{min_length})"
|
||||||
name_already_taken: "'%{name}' is already taken as a custom field name"
|
name_already_taken: "'%{name}' is already taken as a custom field name"
|
||||||
save_default: "Failed to save custom field '%{name}'"
|
save_default: "Failed to save custom field '%{name}'"
|
||||||
|
pro_type: "%{type} custom fields require PRO Subscription"
|
||||||
|
|
||||||
field:
|
field:
|
||||||
too_short: "%{label} must be at least %{min} characters"
|
too_short: "%{label} must be at least %{min} characters"
|
||||||
|
@ -49,6 +50,7 @@ en:
|
||||||
required: "%{property} is required"
|
required: "%{property} is required"
|
||||||
conflict: "Wizard with id '%{wizard_id}' already exists"
|
conflict: "Wizard with id '%{wizard_id}' already exists"
|
||||||
after_time: "After time setting is invalid"
|
after_time: "After time setting is invalid"
|
||||||
|
pro: "%{type} %{property} is PRO only"
|
||||||
|
|
||||||
site_settings:
|
site_settings:
|
||||||
custom_wizard_enabled: "Enable custom wizards."
|
custom_wizard_enabled: "Enable custom wizards."
|
||||||
|
|
|
@ -43,5 +43,11 @@ Discourse::Application.routes.append do
|
||||||
get 'admin/wizards/manager/export' => 'admin_manager#export'
|
get 'admin/wizards/manager/export' => 'admin_manager#export'
|
||||||
post 'admin/wizards/manager/import' => 'admin_manager#import'
|
post 'admin/wizards/manager/import' => 'admin_manager#import'
|
||||||
delete 'admin/wizards/manager/destroy' => 'admin_manager#destroy'
|
delete 'admin/wizards/manager/destroy' => 'admin_manager#destroy'
|
||||||
|
|
||||||
|
get 'admin/wizards/pro' => 'admin_pro#index'
|
||||||
|
get 'admin/wizards/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'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
class CustomWizard::AdminCustomFieldsController < CustomWizard::AdminController
|
class CustomWizard::AdminCustomFieldsController < CustomWizard::AdminController
|
||||||
def index
|
def index
|
||||||
render_json_dump(custom_field_list)
|
render_json_dump(
|
||||||
|
custom_fields: custom_field_list,
|
||||||
|
pro_subscribed: CustomWizard::Pro.subscribed?
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
|
48
controllers/custom_wizard/admin/pro.rb
Normale Datei
48
controllers/custom_wizard/admin/pro.rb
Normale Datei
|
@ -0,0 +1,48 @@
|
||||||
|
# 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
|
|
@ -10,7 +10,8 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
||||||
),
|
),
|
||||||
field_types: CustomWizard::Field.types,
|
field_types: CustomWizard::Field.types,
|
||||||
realtime_validations: CustomWizard::RealtimeValidation.types,
|
realtime_validations: CustomWizard::RealtimeValidation.types,
|
||||||
custom_fields: custom_field_list
|
custom_fields: custom_field_list,
|
||||||
|
pro_subscribed: CustomWizard::Pro.subscribed?
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ class CustomWizard::WizardController < ::ApplicationController
|
||||||
layout 'wizard'
|
layout 'wizard'
|
||||||
|
|
||||||
before_action :ensure_plugin_enabled
|
before_action :ensure_plugin_enabled
|
||||||
|
before_action :update_pro_subscription, only: [:index]
|
||||||
helper_method :wizard_page_title
|
helper_method :wizard_page_title
|
||||||
helper_method :wizard_theme_id
|
helper_method :wizard_theme_id
|
||||||
helper_method :wizard_theme_lookup
|
helper_method :wizard_theme_lookup
|
||||||
|
@ -82,4 +83,8 @@ class CustomWizard::WizardController < ::ApplicationController
|
||||||
redirect_to path("/")
|
redirect_to path("/")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update_pro_subscription
|
||||||
|
CustomWizard::Pro.update_subscription
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"result": {
|
"result": {
|
||||||
"line": 91.83
|
"line": 91.96
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
9
jobs/scheduled/update_pro_subscription.rb
Normale Datei
9
jobs/scheduled/update_pro_subscription.rb
Normale Datei
|
@ -0,0 +1,9 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class CustomWizard::UpdateProSubscription < ::Jobs::Scheduled
|
||||||
|
every 1.hour
|
||||||
|
|
||||||
|
def execute(args = {})
|
||||||
|
CustomWizard::Pro.update_subscription
|
||||||
|
end
|
||||||
|
end
|
|
@ -749,4 +749,8 @@ class CustomWizard::Action
|
||||||
@log.join('; ')
|
@log.join('; ')
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def pro_actions
|
||||||
|
%w[send_message watch_categories send_to_api create_group create_category]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,13 +21,6 @@ class CustomWizard::Builder
|
||||||
@sorted_handlers.sort_by! { |h| -h[:priority] }
|
@sorted_handlers.sort_by! { |h| -h[:priority] }
|
||||||
end
|
end
|
||||||
|
|
||||||
def mapper
|
|
||||||
CustomWizard::Mapper.new(
|
|
||||||
user: @wizard.user,
|
|
||||||
data: @wizard.current_submission&.fields_and_meta
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
def build(build_opts = {}, params = {})
|
def build(build_opts = {}, params = {})
|
||||||
return nil if !SiteSetting.custom_wizard_enabled || !@wizard
|
return nil if !SiteSetting.custom_wizard_enabled || !@wizard
|
||||||
return @wizard if !@wizard.can_access? && !build_opts[:force]
|
return @wizard if !@wizard.can_access? && !build_opts[:force]
|
||||||
|
@ -79,6 +72,32 @@ class CustomWizard::Builder
|
||||||
@wizard
|
@wizard
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def check_condition(template)
|
||||||
|
if template['condition'].present?
|
||||||
|
result = CustomWizard::Mapper.new(
|
||||||
|
inputs: template['condition'],
|
||||||
|
user: @wizard.user,
|
||||||
|
data: @wizard.current_submission&.fields_and_meta,
|
||||||
|
opts: {
|
||||||
|
multiple: true
|
||||||
|
}
|
||||||
|
).perform
|
||||||
|
|
||||||
|
result.any?
|
||||||
|
else
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def mapper
|
||||||
|
CustomWizard::Mapper.new(
|
||||||
|
user: @wizard.user,
|
||||||
|
data: @wizard.current_submission&.fields_and_meta
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def append_field(step, step_template, field_template, build_opts)
|
def append_field(step, step_template, field_template, build_opts)
|
||||||
params = {
|
params = {
|
||||||
id: field_template['id'],
|
id: field_template['id'],
|
||||||
|
@ -222,23 +241,6 @@ class CustomWizard::Builder
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_condition(template)
|
|
||||||
if template['condition'].present?
|
|
||||||
result = CustomWizard::Mapper.new(
|
|
||||||
inputs: template['condition'],
|
|
||||||
user: @wizard.user,
|
|
||||||
data: @wizard.current_submission&.fields_and_meta,
|
|
||||||
opts: {
|
|
||||||
multiple: true
|
|
||||||
}
|
|
||||||
).perform
|
|
||||||
|
|
||||||
result.any?
|
|
||||||
else
|
|
||||||
true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_if_permitted(step, step_template)
|
def check_if_permitted(step, step_template)
|
||||||
step.permitted = true
|
step.permitted = true
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,9 @@ class ::CustomWizard::CustomField
|
||||||
category: ["basic_category"],
|
category: ["basic_category"],
|
||||||
post: ["post"]
|
post: ["post"]
|
||||||
}
|
}
|
||||||
|
PRO_CLASSES ||= ['category', 'group']
|
||||||
TYPES ||= ["string", "boolean", "integer", "json"]
|
TYPES ||= ["string", "boolean", "integer", "json"]
|
||||||
|
PRO_TYPES ||= ["json"]
|
||||||
LIST_CACHE_KEY ||= 'custom_field_list'
|
LIST_CACHE_KEY ||= 'custom_field_list'
|
||||||
|
|
||||||
def self.serializers
|
def self.serializers
|
||||||
|
@ -37,6 +39,8 @@ class ::CustomWizard::CustomField
|
||||||
send("#{attr}=", value)
|
send("#{attr}=", value)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@pro = CustomWizard::Pro.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def save
|
def save
|
||||||
|
@ -81,6 +85,10 @@ class ::CustomWizard::CustomField
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if attr == 'klass' && PRO_CLASSES.include?(value) && !@pro.subscribed?
|
||||||
|
add_error(I18n.t("wizard.custom_field.error.pro_type", type: value))
|
||||||
|
end
|
||||||
|
|
||||||
if attr == 'serializers' && (unsupported = value - CLASSES[klass.to_sym]).length > 0
|
if attr == 'serializers' && (unsupported = value - CLASSES[klass.to_sym]).length > 0
|
||||||
add_error(I18n.t("#{i18n_key}.unsupported_serializers",
|
add_error(I18n.t("#{i18n_key}.unsupported_serializers",
|
||||||
class: klass,
|
class: klass,
|
||||||
|
@ -92,6 +100,10 @@ class ::CustomWizard::CustomField
|
||||||
add_error(I18n.t("#{i18n_key}.unsupported_type", type: value))
|
add_error(I18n.t("#{i18n_key}.unsupported_type", type: value))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if attr == 'type' && PRO_TYPES.include?(value) && !@pro.subscribed?
|
||||||
|
add_error(I18n.t("wizard.custom_field.error.pro_type", type: value))
|
||||||
|
end
|
||||||
|
|
||||||
if attr == 'name'
|
if attr == 'name'
|
||||||
unless value.is_a?(String)
|
unless value.is_a?(String)
|
||||||
add_error(I18n.t("#{i18n_key}.name_invalid", name: value))
|
add_error(I18n.t("#{i18n_key}.name_invalid", name: value))
|
||||||
|
|
|
@ -47,6 +47,7 @@ class CustomWizard::Mapper
|
||||||
@data = params[:data] || {}
|
@data = params[:data] || {}
|
||||||
@user = params[:user]
|
@user = params[:user]
|
||||||
@opts = params[:opts] || {}
|
@opts = params[:opts] || {}
|
||||||
|
@pro = CustomWizard::Pro.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
@ -251,7 +252,7 @@ class CustomWizard::Mapper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if opts[:template]
|
if opts[:template] && @pro.subscribed?
|
||||||
template = Liquid::Template.parse(string)
|
template = Liquid::Template.parse(string)
|
||||||
string = template.render(data)
|
string = template.render(data)
|
||||||
end
|
end
|
||||||
|
|
186
lib/custom_wizard/pro.rb
Normale Datei
186
lib/custom_wizard/pro.rb
Normale Datei
|
@ -0,0 +1,186 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class CustomWizard::Pro
|
||||||
|
include ActiveModel::Serialization
|
||||||
|
|
||||||
|
attr_accessor :authentication,
|
||||||
|
:subscription
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@authentication = CustomWizard::ProAuthentication.new(get_authentication)
|
||||||
|
@subscription = CustomWizard::ProSubscription.new(get_subscription)
|
||||||
|
end
|
||||||
|
|
||||||
|
def authorized?
|
||||||
|
@authentication.active?
|
||||||
|
end
|
||||||
|
|
||||||
|
def subscribed?
|
||||||
|
@subscription.active?
|
||||||
|
end
|
||||||
|
|
||||||
|
def server
|
||||||
|
"test.thepavilion.io"
|
||||||
|
end
|
||||||
|
|
||||||
|
def subscription_type
|
||||||
|
"stripe"
|
||||||
|
end
|
||||||
|
|
||||||
|
def client_name
|
||||||
|
"custom-wizard"
|
||||||
|
end
|
||||||
|
|
||||||
|
def scope
|
||||||
|
"discourse-subscription-server:user_subscription"
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_subscription
|
||||||
|
if @authentication.active?
|
||||||
|
response = Excon.get(
|
||||||
|
"https://#{server}/subscription-server/user-subscriptions/#{subscription_type}/#{client_name}",
|
||||||
|
headers: {
|
||||||
|
"User-Api-Key" => @authentication.api_key
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if response.status == 200
|
||||||
|
begin
|
||||||
|
data = JSON.parse(response.body).deep_symbolize_keys
|
||||||
|
rescue JSON::ParserError
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return false unless data && data.is_a?(Hash)
|
||||||
|
subscriptions = data[:subscriptions]
|
||||||
|
|
||||||
|
if subscriptions.present? && type = subscriptions.first[:price_nickname]
|
||||||
|
@subscription = set_subscription(type)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
destroy_subscription
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy_subscription
|
||||||
|
if remove_subscription
|
||||||
|
@subscription = CustomWizard::ProSubscription.new(get_subscription)
|
||||||
|
!@subscription.active?
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def authentication_url(user_id, request_id)
|
||||||
|
keys = @authentication.generate_keys(user_id, request_id)
|
||||||
|
params = {
|
||||||
|
public_key: keys.public_key,
|
||||||
|
nonce: keys.nonce,
|
||||||
|
client_id: @authentication.client_id,
|
||||||
|
auth_redirect: "#{Discourse.base_url}/admin/wizards/pro/authorize/callback",
|
||||||
|
application_name: SiteSetting.title,
|
||||||
|
scopes: scope
|
||||||
|
}
|
||||||
|
|
||||||
|
uri = URI.parse("https://#{server}/user-api-key/new")
|
||||||
|
uri.query = URI.encode_www_form(params)
|
||||||
|
uri.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def authentication_response(request_id, payload)
|
||||||
|
data = @authentication.decrypt_payload(request_id, payload)
|
||||||
|
return false unless data.is_a?(Hash) && data[:key] && data[:user_id]
|
||||||
|
|
||||||
|
api_key = data[:key]
|
||||||
|
user_id = data[:user_id]
|
||||||
|
user = User.find(user_id)
|
||||||
|
|
||||||
|
if user&.admin
|
||||||
|
@authentication = set_authentication(api_key, user.id)
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy_authentication
|
||||||
|
if remove_authentication
|
||||||
|
@authentication = CustomWizard::ProAuthentication.new(get_authentication)
|
||||||
|
!@authentication.active?
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.subscribed?
|
||||||
|
self.new.subscribed?
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.authorized?
|
||||||
|
self.new.authorized?
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.update_subscription
|
||||||
|
self.new.update_subscription
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.namespace
|
||||||
|
"custom_wizard_pro"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def subscription_db_key
|
||||||
|
"subscription"
|
||||||
|
end
|
||||||
|
|
||||||
|
def authentication_db_key
|
||||||
|
"authentication"
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_subscription
|
||||||
|
raw = PluginStore.get(self.class.namespace, subscription_db_key)
|
||||||
|
|
||||||
|
if raw.present?
|
||||||
|
OpenStruct.new(
|
||||||
|
type: raw['type'],
|
||||||
|
updated_at: raw['updated_at']
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_subscription
|
||||||
|
PluginStore.remove(self.class.namespace, subscription_db_key)
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_subscription(type)
|
||||||
|
PluginStore.set(CustomWizard::Pro.namespace, subscription_db_key, type: type, updated_at: Time.now)
|
||||||
|
CustomWizard::ProSubscription.new(get_subscription)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_authentication
|
||||||
|
raw = PluginStore.get(self.class.namespace, authentication_db_key)
|
||||||
|
OpenStruct.new(
|
||||||
|
key: raw && raw['key'],
|
||||||
|
auth_by: raw && raw['auth_by'],
|
||||||
|
auth_at: raw && raw['auth_at']
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_authentication(key, user_id)
|
||||||
|
PluginStore.set(self.class.namespace, authentication_db_key,
|
||||||
|
key: key,
|
||||||
|
auth_by: user_id,
|
||||||
|
auth_at: Time.now
|
||||||
|
)
|
||||||
|
CustomWizard::ProAuthentication.new(get_authentication)
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_authentication
|
||||||
|
PluginStore.remove(self.class.namespace, authentication_db_key)
|
||||||
|
get_authentication
|
||||||
|
end
|
||||||
|
end
|
95
lib/custom_wizard/pro/authentication.rb
Normale Datei
95
lib/custom_wizard/pro/authentication.rb
Normale Datei
|
@ -0,0 +1,95 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
class CustomWizard::ProAuthentication
|
||||||
|
include ActiveModel::Serialization
|
||||||
|
|
||||||
|
attr_reader :client_id,
|
||||||
|
:auth_by,
|
||||||
|
:auth_at,
|
||||||
|
:api_key
|
||||||
|
|
||||||
|
def initialize(auth)
|
||||||
|
if auth
|
||||||
|
@api_key = auth.key
|
||||||
|
@auth_at = auth.auth_at
|
||||||
|
@auth_by = auth.auth_by
|
||||||
|
end
|
||||||
|
|
||||||
|
@client_id = get_client_id || set_client_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def active?
|
||||||
|
@api_key.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_keys(user_id, request_id)
|
||||||
|
rsa = OpenSSL::PKey::RSA.generate(2048)
|
||||||
|
nonce = SecureRandom.hex(32)
|
||||||
|
set_keys(request_id, user_id, rsa, nonce)
|
||||||
|
|
||||||
|
OpenStruct.new(nonce: nonce, public_key: rsa.public_key)
|
||||||
|
end
|
||||||
|
|
||||||
|
def decrypt_payload(request_id, payload)
|
||||||
|
keys = get_keys(request_id)
|
||||||
|
|
||||||
|
return false unless keys.present? && keys.pem
|
||||||
|
delete_keys(request_id)
|
||||||
|
|
||||||
|
rsa = OpenSSL::PKey::RSA.new(keys.pem)
|
||||||
|
decrypted_payload = rsa.private_decrypt(Base64.decode64(payload))
|
||||||
|
|
||||||
|
return false unless decrypted_payload.present?
|
||||||
|
|
||||||
|
begin
|
||||||
|
data = JSON.parse(decrypted_payload).symbolize_keys
|
||||||
|
rescue JSON::ParserError
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return false unless data[:nonce] == keys.nonce
|
||||||
|
data[:user_id] = keys.user_id
|
||||||
|
|
||||||
|
data
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_keys(request_id)
|
||||||
|
raw = PluginStore.get(CustomWizard::Pro.namespace, "#{keys_db_key}_#{request_id}")
|
||||||
|
OpenStruct.new(
|
||||||
|
user_id: raw && raw['user_id'],
|
||||||
|
pem: raw && raw['pem'],
|
||||||
|
nonce: raw && raw['nonce']
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def keys_db_key
|
||||||
|
"keys"
|
||||||
|
end
|
||||||
|
|
||||||
|
def client_id_db_key
|
||||||
|
"client_id"
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_keys(request_id, user_id, rsa, nonce)
|
||||||
|
PluginStore.set(CustomWizard::Pro.namespace, "#{keys_db_key}_#{request_id}",
|
||||||
|
user_id: user_id,
|
||||||
|
pem: rsa.export,
|
||||||
|
nonce: nonce
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_keys(request_id)
|
||||||
|
PluginStore.remove(CustomWizard::Pro.namespace, "#{keys_db_key}_#{request_id}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_client_id
|
||||||
|
PluginStore.get(CustomWizard::Pro.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)
|
||||||
|
client_id
|
||||||
|
end
|
||||||
|
end
|
22
lib/custom_wizard/pro/subscription.rb
Normale Datei
22
lib/custom_wizard/pro/subscription.rb
Normale Datei
|
@ -0,0 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
class CustomWizard::ProSubscription
|
||||||
|
include ActiveModel::Serialization
|
||||||
|
|
||||||
|
attr_reader :type,
|
||||||
|
:updated_at
|
||||||
|
|
||||||
|
def initialize(subscription)
|
||||||
|
if subscription
|
||||||
|
@type = subscription.type
|
||||||
|
@updated_at = subscription.updated_at
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def types
|
||||||
|
%w(community business)
|
||||||
|
end
|
||||||
|
|
||||||
|
def active?
|
||||||
|
types.include?(type) && updated_at.to_datetime > (Time.zone.now - 2.hours).to_datetime
|
||||||
|
end
|
||||||
|
end
|
|
@ -6,6 +6,7 @@ class CustomWizard::TemplateValidator
|
||||||
def initialize(data, opts = {})
|
def initialize(data, opts = {})
|
||||||
@data = data
|
@data = data
|
||||||
@opts = opts
|
@opts = opts
|
||||||
|
@pro = CustomWizard::Pro.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
@ -14,12 +15,15 @@ class CustomWizard::TemplateValidator
|
||||||
check_id(data, :wizard)
|
check_id(data, :wizard)
|
||||||
check_required(data, :wizard)
|
check_required(data, :wizard)
|
||||||
validate_after_time
|
validate_after_time
|
||||||
|
validate_pro(data, :wizard)
|
||||||
|
|
||||||
data[:steps].each do |step|
|
data[:steps].each do |step|
|
||||||
check_required(step, :step)
|
check_required(step, :step)
|
||||||
|
validate_pro(step, :step)
|
||||||
|
|
||||||
if data[:fields].present?
|
if step[:fields].present?
|
||||||
data[:fields].each do |field|
|
step[:fields].each do |field|
|
||||||
|
validate_pro(field, :field)
|
||||||
check_required(field, :field)
|
check_required(field, :field)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -27,6 +31,7 @@ class CustomWizard::TemplateValidator
|
||||||
|
|
||||||
if data[:actions].present?
|
if data[:actions].present?
|
||||||
data[:actions].each do |action|
|
data[:actions].each do |action|
|
||||||
|
validate_pro(action, :action)
|
||||||
check_required(action, :action)
|
check_required(action, :action)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -47,16 +52,53 @@ class CustomWizard::TemplateValidator
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.pro
|
||||||
|
{
|
||||||
|
wizard: {},
|
||||||
|
step: {
|
||||||
|
condition: 'present',
|
||||||
|
index: 'conditional'
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
condition: 'present',
|
||||||
|
index: 'conditional'
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
type: %w[
|
||||||
|
send_message
|
||||||
|
add_to_group
|
||||||
|
create_category
|
||||||
|
create_group
|
||||||
|
send_to_api
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def check_required(object, type)
|
def check_required(object, type)
|
||||||
CustomWizard::TemplateValidator.required[type].each do |property|
|
self.class.required[type].each do |property|
|
||||||
if object[property].blank?
|
if object[property].blank?
|
||||||
errors.add :base, I18n.t("wizard.validation.required", property: property)
|
errors.add :base, I18n.t("wizard.validation.required", property: property)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def validate_pro(object, type)
|
||||||
|
self.class.pro[type].each do |property, pro_type|
|
||||||
|
is_pro = object[property.to_s].present? && (
|
||||||
|
pro_type === 'present' ||
|
||||||
|
(pro_type === 'conditional' && object[property.to_s].is_a?(Hash)) ||
|
||||||
|
(pro_type.is_a?(Array) && pro_type.include?(object[property.to_s]))
|
||||||
|
)
|
||||||
|
|
||||||
|
if is_pro && !@pro.subscribed?
|
||||||
|
errors.add :base, I18n.t("wizard.validation.pro", type: type.to_s, property: property)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def check_id(object, type)
|
def check_id(object, type)
|
||||||
if type === :wizard && @opts[:create] && CustomWizard::Template.exists?(object[:id])
|
if type === :wizard && @opts[:create] && CustomWizard::Template.exists?(object[:id])
|
||||||
errors.add :base, I18n.t("wizard.validation.conflict", wizard_id: object[:id])
|
errors.add :base, I18n.t("wizard.validation.conflict", wizard_id: object[:id])
|
||||||
|
|
|
@ -310,10 +310,10 @@ class CustomWizard::Wizard
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.list(user, template_opts: {}, not_completed: false)
|
def self.list(user, template_opts = {}, not_completed = false)
|
||||||
return [] unless user
|
return [] unless user
|
||||||
|
|
||||||
CustomWizard::Template.list(template_opts).reduce([]) do |result, template|
|
CustomWizard::Template.list(**template_opts).reduce([]) do |result, template|
|
||||||
wizard = new(template, user)
|
wizard = new(template, user)
|
||||||
result.push(wizard) if wizard.can_access? && (
|
result.push(wizard) if wizard.can_access? && (
|
||||||
!not_completed || !wizard.completed?
|
!not_completed || !wizard.completed?
|
||||||
|
@ -325,7 +325,7 @@ class CustomWizard::Wizard
|
||||||
def self.after_signup(user)
|
def self.after_signup(user)
|
||||||
wizards = list(
|
wizards = list(
|
||||||
user,
|
user,
|
||||||
template_opts: {
|
{
|
||||||
setting: 'after_signup',
|
setting: 'after_signup',
|
||||||
order: "(value::json ->> 'permitted') IS NOT NULL DESC"
|
order: "(value::json ->> 'permitted') IS NOT NULL DESC"
|
||||||
}
|
}
|
||||||
|
@ -336,11 +336,11 @@ class CustomWizard::Wizard
|
||||||
def self.prompt_completion(user)
|
def self.prompt_completion(user)
|
||||||
wizards = list(
|
wizards = list(
|
||||||
user,
|
user,
|
||||||
template_opts: {
|
{
|
||||||
setting: 'prompt_completion',
|
setting: 'prompt_completion',
|
||||||
order: "(value::json ->> 'permitted') IS NOT NULL DESC"
|
order: "(value::json ->> 'permitted') IS NOT NULL DESC"
|
||||||
},
|
},
|
||||||
not_completed: true
|
true
|
||||||
)
|
)
|
||||||
if wizards.any?
|
if wizards.any?
|
||||||
wizards.map do |w|
|
wizards.map do |w|
|
||||||
|
|
12
plugin.rb
12
plugin.rb
|
@ -71,11 +71,13 @@ after_initialize do
|
||||||
../controllers/custom_wizard/admin/logs.rb
|
../controllers/custom_wizard/admin/logs.rb
|
||||||
../controllers/custom_wizard/admin/manager.rb
|
../controllers/custom_wizard/admin/manager.rb
|
||||||
../controllers/custom_wizard/admin/custom_fields.rb
|
../controllers/custom_wizard/admin/custom_fields.rb
|
||||||
|
../controllers/custom_wizard/admin/pro.rb
|
||||||
../controllers/custom_wizard/wizard.rb
|
../controllers/custom_wizard/wizard.rb
|
||||||
../controllers/custom_wizard/steps.rb
|
../controllers/custom_wizard/steps.rb
|
||||||
../controllers/custom_wizard/realtime_validations.rb
|
../controllers/custom_wizard/realtime_validations.rb
|
||||||
../jobs/refresh_api_access_token.rb
|
../jobs/regular/refresh_api_access_token.rb
|
||||||
../jobs/set_after_time_wizard.rb
|
../jobs/regular/set_after_time_wizard.rb
|
||||||
|
../jobs/scheduled/update_pro_subscription.rb
|
||||||
../lib/custom_wizard/validators/template.rb
|
../lib/custom_wizard/validators/template.rb
|
||||||
../lib/custom_wizard/validators/update.rb
|
../lib/custom_wizard/validators/update.rb
|
||||||
../lib/custom_wizard/action_result.rb
|
../lib/custom_wizard/action_result.rb
|
||||||
|
@ -94,6 +96,9 @@ after_initialize do
|
||||||
../lib/custom_wizard/submission.rb
|
../lib/custom_wizard/submission.rb
|
||||||
../lib/custom_wizard/template.rb
|
../lib/custom_wizard/template.rb
|
||||||
../lib/custom_wizard/wizard.rb
|
../lib/custom_wizard/wizard.rb
|
||||||
|
../lib/custom_wizard/pro.rb
|
||||||
|
../lib/custom_wizard/pro/subscription.rb
|
||||||
|
../lib/custom_wizard/pro/authentication.rb
|
||||||
../lib/custom_wizard/api/api.rb
|
../lib/custom_wizard/api/api.rb
|
||||||
../lib/custom_wizard/api/authorization.rb
|
../lib/custom_wizard/api/authorization.rb
|
||||||
../lib/custom_wizard/api/endpoint.rb
|
../lib/custom_wizard/api/endpoint.rb
|
||||||
|
@ -114,6 +119,9 @@ after_initialize do
|
||||||
../serializers/custom_wizard/log_serializer.rb
|
../serializers/custom_wizard/log_serializer.rb
|
||||||
../serializers/custom_wizard/submission_serializer.rb
|
../serializers/custom_wizard/submission_serializer.rb
|
||||||
../serializers/custom_wizard/realtime_validation/similar_topics_serializer.rb
|
../serializers/custom_wizard/realtime_validation/similar_topics_serializer.rb
|
||||||
|
../serializers/custom_wizard/pro/authentication_serializer.rb
|
||||||
|
../serializers/custom_wizard/pro/subscription_serializer.rb
|
||||||
|
../serializers/custom_wizard/pro_serializer.rb
|
||||||
../extensions/extra_locales_controller.rb
|
../extensions/extra_locales_controller.rb
|
||||||
../extensions/invites_controller.rb
|
../extensions/invites_controller.rb
|
||||||
../extensions/users_controller.rb
|
../extensions/users_controller.rb
|
||||||
|
|
11
serializers/custom_wizard/pro/authentication_serializer.rb
Normale Datei
11
serializers/custom_wizard/pro/authentication_serializer.rb
Normale Datei
|
@ -0,0 +1,11 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
class CustomWizard::ProAuthenticationSerializer < ApplicationSerializer
|
||||||
|
attributes :active,
|
||||||
|
:client_id,
|
||||||
|
:auth_by,
|
||||||
|
:auth_at
|
||||||
|
|
||||||
|
def active
|
||||||
|
object.active?
|
||||||
|
end
|
||||||
|
end
|
10
serializers/custom_wizard/pro/subscription_serializer.rb
Normale Datei
10
serializers/custom_wizard/pro/subscription_serializer.rb
Normale Datei
|
@ -0,0 +1,10 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
class CustomWizard::ProSubscriptionSerializer < ApplicationSerializer
|
||||||
|
attributes :type,
|
||||||
|
:active,
|
||||||
|
:updated_at
|
||||||
|
|
||||||
|
def active
|
||||||
|
object.active?
|
||||||
|
end
|
||||||
|
end
|
6
serializers/custom_wizard/pro_serializer.rb
Normale Datei
6
serializers/custom_wizard/pro_serializer.rb
Normale Datei
|
@ -0,0 +1,6 @@
|
||||||
|
# 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
|
|
@ -6,26 +6,22 @@ describe CustomWizard::Action do
|
||||||
fab!(:category) { Fabricate(:category, name: 'cat1', slug: 'cat-slug') }
|
fab!(:category) { Fabricate(:category, name: 'cat1', slug: 'cat-slug') }
|
||||||
fab!(:group) { Fabricate(:group) }
|
fab!(:group) { Fabricate(:group) }
|
||||||
|
|
||||||
let(:wizard_template) {
|
let(:wizard_template) { get_wizard_fixture("wizard") }
|
||||||
JSON.parse(
|
let(:open_composer) { get_wizard_fixture("actions/open_composer") }
|
||||||
File.open(
|
let(:create_category) { get_wizard_fixture("actions/create_category") }
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
let(:create_group) { get_wizard_fixture("actions/create_group") }
|
||||||
).read
|
let(:add_to_group) { get_wizard_fixture("actions/add_to_group") }
|
||||||
)
|
let(:send_message) { get_wizard_fixture("actions/send_message") }
|
||||||
}
|
let(:send_message_multi) { get_wizard_fixture("actions/send_message_multi") }
|
||||||
|
|
||||||
let(:open_composer) {
|
def update_template(template)
|
||||||
JSON.parse(
|
CustomWizard::Template.save(template, skip_jobs: true)
|
||||||
File.open(
|
@template = CustomWizard::Template.find('super_mega_fun_wizard')
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/actions/open_composer.json"
|
end
|
||||||
).read
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
Group.refresh_automatic_group!(:trust_level_2)
|
Group.refresh_automatic_group!(:trust_level_2)
|
||||||
CustomWizard::Template.save(wizard_template, skip_jobs: true)
|
update_template(wizard_template)
|
||||||
@template = CustomWizard::Template.find('super_mega_fun_wizard')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'creating a topic' do
|
context 'creating a topic' do
|
||||||
|
@ -110,54 +106,6 @@ describe CustomWizard::Action do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'sending a message' do
|
|
||||||
it 'works' do
|
|
||||||
User.create(username: 'angus1', email: "angus1@email.com")
|
|
||||||
|
|
||||||
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
|
||||||
wizard.create_updater(wizard.steps[0].id, {}).update
|
|
||||||
wizard.create_updater(wizard.steps[1].id, {}).update
|
|
||||||
|
|
||||||
topic = Topic.where(
|
|
||||||
archetype: Archetype.private_message,
|
|
||||||
title: "Message title"
|
|
||||||
)
|
|
||||||
|
|
||||||
post = Post.where(
|
|
||||||
topic_id: topic.pluck(:id),
|
|
||||||
raw: "I will interpolate some wizard fields"
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(topic.exists?).to eq(true)
|
|
||||||
expect(topic.first.topic_allowed_users.first.user.username).to eq('angus1')
|
|
||||||
expect(post.exists?).to eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'allows using multiple PM targets' do
|
|
||||||
User.create(username: 'angus1', email: "angus1@email.com")
|
|
||||||
User.create(username: 'faiz', email: "faiz@email.com")
|
|
||||||
Group.create(name: "cool_group")
|
|
||||||
Group.create(name: 'cool_group_1')
|
|
||||||
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
|
||||||
wizard.create_updater(wizard.steps[0].id, {}).update
|
|
||||||
wizard.create_updater(wizard.steps[1].id, {}).update
|
|
||||||
|
|
||||||
topic = Topic.where(
|
|
||||||
archetype: Archetype.private_message,
|
|
||||||
title: "Multiple Recipients title"
|
|
||||||
)
|
|
||||||
|
|
||||||
post = Post.where(
|
|
||||||
topic_id: topic.pluck(:id),
|
|
||||||
raw: "I will interpolate some wizard fields"
|
|
||||||
)
|
|
||||||
expect(topic.exists?).to eq(true)
|
|
||||||
expect(topic.first.all_allowed_users.map(&:username)).to include('angus1', 'faiz')
|
|
||||||
expect(topic.first.allowed_groups.map(&:name)).to include('cool_group', 'cool_group_1')
|
|
||||||
expect(post.exists?).to eq(true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'updates a profile' do
|
it 'updates a profile' do
|
||||||
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
upload = Upload.create!(
|
upload = Upload.create!(
|
||||||
|
@ -182,10 +130,8 @@ describe CustomWizard::Action do
|
||||||
updater = wizard.create_updater(wizard.steps[1].id, {})
|
updater = wizard.create_updater(wizard.steps[1].id, {})
|
||||||
updater.update
|
updater.update
|
||||||
|
|
||||||
category = Category.find_by(id: wizard.current_submission.fields['action_8'])
|
|
||||||
|
|
||||||
expect(updater.result[:redirect_on_next]).to eq(
|
expect(updater.result[:redirect_on_next]).to eq(
|
||||||
"/new-topic?title=Title%20of%20the%20composer%20topic&body=I%20am%20interpolating%20some%20user%20fields%20Angus%20angus%20angus%40email.com&category_id=#{category.id}&tags=tag1"
|
"/new-topic?title=Title%20of%20the%20composer%20topic&body=I%20am%20interpolating%20some%20user%20fields%20Angus%20angus%20angus%40email.com&tags=tag1"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -210,35 +156,11 @@ describe CustomWizard::Action do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates a category' do
|
|
||||||
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
|
||||||
wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update
|
|
||||||
wizard.create_updater(wizard.steps[1].id, {}).update
|
|
||||||
expect(Category.where(id: wizard.current_submission.fields['action_8']).exists?).to eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates a group' do
|
|
||||||
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
|
||||||
wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update
|
|
||||||
expect(Group.where(name: wizard.current_submission.fields['action_9']).exists?).to eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'adds a user to a group' do
|
|
||||||
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
|
||||||
step_id = wizard.steps[0].id
|
|
||||||
updater = wizard.create_updater(step_id, step_1_field_1: "Text input").update
|
|
||||||
group = Group.find_by(name: wizard.current_submission.fields['action_9'])
|
|
||||||
expect(group.users.first.username).to eq('angus')
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'watches categories' do
|
it 'watches categories' do
|
||||||
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update
|
wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update
|
||||||
wizard.create_updater(wizard.steps[1].id, {}).update
|
wizard.create_updater(wizard.steps[1].id, {}).update
|
||||||
expect(CategoryUser.where(
|
|
||||||
category_id: wizard.current_submission.fields['action_8'],
|
|
||||||
user_id: user.id
|
|
||||||
).first.notification_level).to eq(2)
|
|
||||||
expect(CategoryUser.where(
|
expect(CategoryUser.where(
|
||||||
category_id: category.id,
|
category_id: category.id,
|
||||||
user_id: user.id
|
user_id: user.id
|
||||||
|
@ -251,4 +173,97 @@ describe CustomWizard::Action do
|
||||||
updater.update
|
updater.update
|
||||||
expect(updater.result[:redirect_on_next]).to eq("https://google.com")
|
expect(updater.result[:redirect_on_next]).to eq("https://google.com")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "pro actions" do
|
||||||
|
before do
|
||||||
|
enable_pro
|
||||||
|
end
|
||||||
|
|
||||||
|
it '#send_message' do
|
||||||
|
wizard_template['actions'] << send_message
|
||||||
|
update_template(wizard_template)
|
||||||
|
|
||||||
|
User.create(username: 'angus1', email: "angus1@email.com")
|
||||||
|
|
||||||
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
wizard.create_updater(wizard.steps[0].id, {}).update
|
||||||
|
wizard.create_updater(wizard.steps[1].id, {}).update
|
||||||
|
|
||||||
|
topic = Topic.where(
|
||||||
|
archetype: Archetype.private_message,
|
||||||
|
title: "Message title"
|
||||||
|
)
|
||||||
|
|
||||||
|
post = Post.where(
|
||||||
|
topic_id: topic.pluck(:id),
|
||||||
|
raw: "I will interpolate some wizard fields"
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(topic.exists?).to eq(true)
|
||||||
|
expect(topic.first.topic_allowed_users.first.user.username).to eq('angus1')
|
||||||
|
expect(post.exists?).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it '#send_message allows using multiple targets' do
|
||||||
|
wizard_template['actions'] << send_message_multi
|
||||||
|
update_template(wizard_template)
|
||||||
|
|
||||||
|
User.create(username: 'angus1', email: "angus1@email.com")
|
||||||
|
User.create(username: 'faiz', email: "faiz@email.com")
|
||||||
|
Group.create(name: "cool_group")
|
||||||
|
Group.create(name: 'cool_group_1')
|
||||||
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
wizard.create_updater(wizard.steps[0].id, {}).update
|
||||||
|
wizard.create_updater(wizard.steps[1].id, {}).update
|
||||||
|
|
||||||
|
topic = Topic.where(
|
||||||
|
archetype: Archetype.private_message,
|
||||||
|
title: "Multiple Recipients title"
|
||||||
|
)
|
||||||
|
|
||||||
|
post = Post.where(
|
||||||
|
topic_id: topic.pluck(:id),
|
||||||
|
raw: "I will interpolate some wizard fields"
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(topic.exists?).to eq(true)
|
||||||
|
expect(topic.first.all_allowed_users.map(&:username)).to include('angus1', 'faiz')
|
||||||
|
expect(topic.first.allowed_groups.map(&:name)).to include('cool_group', 'cool_group_1')
|
||||||
|
expect(post.exists?).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it '#create_category' do
|
||||||
|
wizard_template['actions'] << create_category
|
||||||
|
update_template(wizard_template)
|
||||||
|
|
||||||
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update
|
||||||
|
wizard.create_updater(wizard.steps[1].id, {}).update
|
||||||
|
|
||||||
|
expect(Category.where(id: wizard.current_submission.fields['action_8']).exists?).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it '#create_group' do
|
||||||
|
wizard_template['actions'] << create_group
|
||||||
|
update_template(wizard_template)
|
||||||
|
|
||||||
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update
|
||||||
|
|
||||||
|
expect(Group.where(name: wizard.current_submission.fields['action_9']).exists?).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it '#add_to_group' do
|
||||||
|
wizard_template['actions'] << create_group
|
||||||
|
wizard_template['actions'] << add_to_group
|
||||||
|
update_template(wizard_template)
|
||||||
|
|
||||||
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
step_id = wizard.steps[0].id
|
||||||
|
updater = wizard.create_updater(step_id, step_1_field_1: "Text input").update
|
||||||
|
group = Group.find_by(name: wizard.current_submission.fields['action_9'])
|
||||||
|
|
||||||
|
expect(group.users.first.username).to eq('angus')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,45 +15,15 @@ describe CustomWizard::Builder do
|
||||||
fab!(:category2) { Fabricate(:category, name: 'cat2') }
|
fab!(:category2) { Fabricate(:category, name: 'cat2') }
|
||||||
fab!(:group) { Fabricate(:group) }
|
fab!(:group) { Fabricate(:group) }
|
||||||
|
|
||||||
let(:required_data_json) {
|
let(:wizard_template) { get_wizard_fixture("wizard") }
|
||||||
JSON.parse(
|
let(:required_data_json) { get_wizard_fixture("step/required_data") }
|
||||||
File.open(
|
let(:permitted_json) { get_wizard_fixture("wizard/permitted") }
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/step/required_data.json"
|
let(:permitted_param_json) { get_wizard_fixture("step/permitted_params") }
|
||||||
).read
|
let(:user_condition_json) { get_wizard_fixture("condition/user_condition") }
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let(:permitted_json) {
|
|
||||||
JSON.parse(
|
|
||||||
File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/permitted.json"
|
|
||||||
).read
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let(:permitted_param_json) {
|
|
||||||
JSON.parse(
|
|
||||||
File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/step/permitted_params.json"
|
|
||||||
).read
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let(:user_condition_json) {
|
|
||||||
JSON.parse(
|
|
||||||
File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/condition/user_condition.json"
|
|
||||||
).read
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
Group.refresh_automatic_group!(:trust_level_3)
|
Group.refresh_automatic_group!(:trust_level_3)
|
||||||
CustomWizard::Template.save(
|
CustomWizard::Template.save(wizard_template, skip_jobs: true)
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read),
|
|
||||||
skip_jobs: true)
|
|
||||||
@template = CustomWizard::Template.find('super_mega_fun_wizard')
|
@template = CustomWizard::Template.find('super_mega_fun_wizard')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -283,6 +253,7 @@ describe CustomWizard::Builder do
|
||||||
|
|
||||||
context "with condition" do
|
context "with condition" do
|
||||||
before do
|
before do
|
||||||
|
enable_pro
|
||||||
@template[:steps][0][:condition] = user_condition_json['condition']
|
@template[:steps][0][:condition] = user_condition_json['condition']
|
||||||
CustomWizard::Template.save(@template.as_json)
|
CustomWizard::Template.save(@template.as_json)
|
||||||
end
|
end
|
||||||
|
@ -321,6 +292,7 @@ describe CustomWizard::Builder do
|
||||||
|
|
||||||
context "with condition" do
|
context "with condition" do
|
||||||
before do
|
before do
|
||||||
|
enable_pro
|
||||||
@template[:steps][0][:fields][0][:condition] = user_condition_json['condition']
|
@template[:steps][0][:fields][0][:condition] = user_condition_json['condition']
|
||||||
CustomWizard::Template.save(@template.as_json)
|
CustomWizard::Template.save(@template.as_json)
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,12 +3,8 @@
|
||||||
require_relative '../../plugin_helper'
|
require_relative '../../plugin_helper'
|
||||||
|
|
||||||
describe CustomWizard::CustomField do
|
describe CustomWizard::CustomField do
|
||||||
|
let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") }
|
||||||
let(:custom_field_json) {
|
let(:custom_field_pro_json) { get_wizard_fixture("custom_field/pro_custom_fields") }
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/custom_field/custom_fields.json"
|
|
||||||
).read)
|
|
||||||
}
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
CustomWizard::CustomField.invalidate_cache
|
CustomWizard::CustomField.invalidate_cache
|
||||||
|
@ -104,8 +100,8 @@ describe CustomWizard::CustomField do
|
||||||
|
|
||||||
it "does not save with an unsupported serializer" do
|
it "does not save with an unsupported serializer" do
|
||||||
invalid_field_json = custom_field_json['custom_fields'].first
|
invalid_field_json = custom_field_json['custom_fields'].first
|
||||||
invalid_field_json['klass'] = 'category'
|
invalid_field_json['klass'] = 'post'
|
||||||
invalid_field_json['serializers'] = ['category', 'site_category']
|
invalid_field_json['serializers'] = ['post', 'post_revision']
|
||||||
|
|
||||||
custom_field = CustomWizard::CustomField.new(nil, invalid_field_json)
|
custom_field = CustomWizard::CustomField.new(nil, invalid_field_json)
|
||||||
|
|
||||||
|
@ -113,8 +109,8 @@ describe CustomWizard::CustomField do
|
||||||
expect(custom_field.valid?).to eq(false)
|
expect(custom_field.valid?).to eq(false)
|
||||||
expect(custom_field.errors.full_messages.first).to eq(
|
expect(custom_field.errors.full_messages.first).to eq(
|
||||||
I18n.t("wizard.custom_field.error.unsupported_serializers",
|
I18n.t("wizard.custom_field.error.unsupported_serializers",
|
||||||
class: "category",
|
class: "post",
|
||||||
serializers: "category, site_category"
|
serializers: "post_revision"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
expect(
|
expect(
|
||||||
|
@ -196,6 +192,50 @@ describe CustomWizard::CustomField do
|
||||||
).exists?
|
).exists?
|
||||||
).to eq(false)
|
).to eq(false)
|
||||||
end
|
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)
|
||||||
|
|
||||||
|
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")
|
||||||
|
)
|
||||||
|
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)
|
||||||
|
|
||||||
|
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")
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with a pro subscription" do
|
||||||
|
before do
|
||||||
|
enable_pro
|
||||||
|
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)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
expect(custom_field.save).to eq(true)
|
||||||
|
expect(custom_field.valid?).to eq(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "lists" do
|
context "lists" do
|
||||||
|
@ -205,15 +245,15 @@ describe CustomWizard::CustomField do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "lists saved custom field records" do
|
it "saved custom field records" do
|
||||||
expect(CustomWizard::CustomField.list.length).to eq(4)
|
expect(CustomWizard::CustomField.list.length).to eq(2)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "lists saved custom field records by attribute value" do
|
it "saved custom field records by attribute value" do
|
||||||
expect(CustomWizard::CustomField.list_by(:klass, 'topic').length).to eq(1)
|
expect(CustomWizard::CustomField.list_by(:klass, 'topic').length).to eq(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "lists saved custom field records by optional values" do
|
it "saved custom field records by optional values" do
|
||||||
field_json = custom_field_json['custom_fields'].first
|
field_json = custom_field_json['custom_fields'].first
|
||||||
field_json['serializers'] = nil
|
field_json['serializers'] = nil
|
||||||
|
|
||||||
|
@ -221,12 +261,12 @@ describe CustomWizard::CustomField do
|
||||||
expect(CustomWizard::CustomField.list_by(:serializers, ['post']).length).to eq(0)
|
expect(CustomWizard::CustomField.list_by(:serializers, ['post']).length).to eq(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "lists custom field records added by other plugins " do
|
it "custom field records added by other plugins " do
|
||||||
expect(CustomWizard::CustomField.external_list.length).to eq(11)
|
expect(CustomWizard::CustomField.external_list.length).to be > 10
|
||||||
end
|
end
|
||||||
|
|
||||||
it "lists all custom field records" do
|
it "all custom field records" do
|
||||||
expect(CustomWizard::CustomField.full_list.length).to eq(15)
|
expect(CustomWizard::CustomField.full_list.length).to be > 12
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,7 @@
|
||||||
require_relative '../../plugin_helper'
|
require_relative '../../plugin_helper'
|
||||||
|
|
||||||
describe CustomWizard::Field do
|
describe CustomWizard::Field do
|
||||||
let(:field_hash) do
|
let(:field_hash) { get_wizard_fixture("field/field") }
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/field/field.json"
|
|
||||||
).read).with_indifferent_access
|
|
||||||
end
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
CustomWizard::Field.register(
|
CustomWizard::Field.register(
|
||||||
|
|
|
@ -31,16 +31,8 @@ describe CustomWizard::Mapper do
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
let(:inputs) {
|
let(:inputs) { get_wizard_fixture("mapper/inputs") }
|
||||||
JSON.parse(File.open(
|
let(:data) { get_wizard_fixture("mapper/data") }
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/mapper/inputs.json"
|
|
||||||
).read)
|
|
||||||
}
|
|
||||||
let(:data) {
|
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/mapper/data.json"
|
|
||||||
).read)
|
|
||||||
}
|
|
||||||
let(:template_params) {
|
let(:template_params) {
|
||||||
{
|
{
|
||||||
"step_1_field_1" => "Hello"
|
"step_1_field_1" => "Hello"
|
||||||
|
@ -352,7 +344,7 @@ describe CustomWizard::Mapper do
|
||||||
expect(result).to eq(template_params["step_1_field_1"])
|
expect(result).to eq(template_params["step_1_field_1"])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "treats replaced values as string literals" do
|
it "requires a pro subscription" do
|
||||||
template = '{{ "w{step_1_field_1}" | size }}'
|
template = '{{ "w{step_1_field_1}" | size }}'
|
||||||
mapper = create_template_mapper(template_params, user1)
|
mapper = create_template_mapper(template_params, user1)
|
||||||
result = mapper.interpolate(
|
result = mapper.interpolate(
|
||||||
|
@ -362,60 +354,17 @@ describe CustomWizard::Mapper do
|
||||||
wizard: true,
|
wizard: true,
|
||||||
value: true
|
value: true
|
||||||
)
|
)
|
||||||
expect(result).to eq(template_params["step_1_field_1"].size.to_s)
|
expect(result).to eq("{{ \"#{template_params["step_1_field_1"]}\" | size }}")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "allows the wizard values to be used inside conditionals" do
|
context "with a pro subscription" do
|
||||||
template = <<-LIQUID
|
before do
|
||||||
{%- if "w{step_1_field_1}" contains "ello" -%}
|
enable_pro
|
||||||
Correct
|
end
|
||||||
{%- else -%}
|
|
||||||
Incorrect
|
|
||||||
{%-endif-%}
|
|
||||||
LIQUID
|
|
||||||
mapper = create_template_mapper(template_params, user1)
|
|
||||||
result = mapper.interpolate(
|
|
||||||
template.dup,
|
|
||||||
template: true,
|
|
||||||
user: true,
|
|
||||||
wizard: true,
|
|
||||||
value: true
|
|
||||||
)
|
|
||||||
expect(result).to eq("Correct")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "can access data passed to render method as variable" do
|
it "treats replaced values as string literals" do
|
||||||
template = "{{step_1_field_1.size}}"
|
template = '{{ "w{step_1_field_1}" | size }}'
|
||||||
mapper = create_template_mapper(template_params, user1)
|
mapper = create_template_mapper(template_params, user1)
|
||||||
result = mapper.interpolate(
|
|
||||||
template.dup,
|
|
||||||
template: true,
|
|
||||||
user: true,
|
|
||||||
wizard: true,
|
|
||||||
value: true
|
|
||||||
)
|
|
||||||
expect(result).to eq(template_params["step_1_field_1"].size.to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "doesn't parse the template when template param is false" do
|
|
||||||
template = <<-LIQUID.strip
|
|
||||||
{{ "w{step_1_field_1}" | size}}
|
|
||||||
LIQUID
|
|
||||||
mapper = create_template_mapper(template_params, user1)
|
|
||||||
result = mapper.interpolate(
|
|
||||||
template.dup,
|
|
||||||
template: false,
|
|
||||||
)
|
|
||||||
expect(result).to eq(template)
|
|
||||||
end
|
|
||||||
|
|
||||||
context "custom filter: 'first_non_empty'" do
|
|
||||||
it "gives first non empty element from list" do
|
|
||||||
template = <<-LIQUID.strip
|
|
||||||
{%- assign entry = "" | first_non_empty: step_1_field_1, step_1_field_2, step_1_field_3 -%}
|
|
||||||
{{ entry }}
|
|
||||||
LIQUID
|
|
||||||
mapper = create_template_mapper(template_params_non_empty, user1)
|
|
||||||
result = mapper.interpolate(
|
result = mapper.interpolate(
|
||||||
template.dup,
|
template.dup,
|
||||||
template: true,
|
template: true,
|
||||||
|
@ -423,15 +372,18 @@ describe CustomWizard::Mapper do
|
||||||
wizard: true,
|
wizard: true,
|
||||||
value: true
|
value: true
|
||||||
)
|
)
|
||||||
expect(result).to eq(template_params_non_empty["step_1_field_3"])
|
expect(result).to eq(template_params["step_1_field_1"].size.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "gives first non empty element from list when multiple non empty values present" do
|
it "allows the wizard values to be used inside conditionals" do
|
||||||
template = <<-LIQUID.strip
|
template = <<-LIQUID
|
||||||
{%- assign entry = "" | first_non_empty: step_1_field_1, step_1_field_2, step_1_field_3 -%}
|
{%- if "w{step_1_field_1}" contains "ello" -%}
|
||||||
{{ entry }}
|
Correct
|
||||||
|
{%- else -%}
|
||||||
|
Incorrect
|
||||||
|
{%-endif-%}
|
||||||
LIQUID
|
LIQUID
|
||||||
mapper = create_template_mapper(template_params_multiple_non_empty, user1)
|
mapper = create_template_mapper(template_params, user1)
|
||||||
result = mapper.interpolate(
|
result = mapper.interpolate(
|
||||||
template.dup,
|
template.dup,
|
||||||
template: true,
|
template: true,
|
||||||
|
@ -439,25 +391,84 @@ describe CustomWizard::Mapper do
|
||||||
wizard: true,
|
wizard: true,
|
||||||
value: true
|
value: true
|
||||||
)
|
)
|
||||||
expect(result).to eq(template_params_multiple_non_empty["step_1_field_2"])
|
expect(result).to eq("Correct")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "gives empty if all elements are empty" do
|
it "can access data passed to render method as variable" do
|
||||||
|
template = "{{step_1_field_1.size}}"
|
||||||
|
mapper = create_template_mapper(template_params, user1)
|
||||||
|
result = mapper.interpolate(
|
||||||
|
template.dup,
|
||||||
|
template: true,
|
||||||
|
user: true,
|
||||||
|
wizard: true,
|
||||||
|
value: true
|
||||||
|
)
|
||||||
|
expect(result).to eq(template_params["step_1_field_1"].size.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't parse the template when template param is false" do
|
||||||
template = <<-LIQUID.strip
|
template = <<-LIQUID.strip
|
||||||
{%- assign entry = "" | first_non_empty: step_1_field_1, step_1_field_2, step_1_field_3 -%}
|
{{ "w{step_1_field_1}" | size}}
|
||||||
{%- if entry -%}
|
LIQUID
|
||||||
|
mapper = create_template_mapper(template_params, user1)
|
||||||
|
result = mapper.interpolate(
|
||||||
|
template.dup,
|
||||||
|
template: false,
|
||||||
|
)
|
||||||
|
expect(result).to eq(template)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "custom filter: 'first_non_empty'" do
|
||||||
|
it "gives first non empty element from list" do
|
||||||
|
template = <<-LIQUID.strip
|
||||||
|
{%- assign entry = "" | first_non_empty: step_1_field_1, step_1_field_2, step_1_field_3 -%}
|
||||||
{{ entry }}
|
{{ entry }}
|
||||||
{%- endif -%}
|
LIQUID
|
||||||
LIQUID
|
mapper = create_template_mapper(template_params_non_empty, user1)
|
||||||
mapper = create_template_mapper(template_params_empty, user1)
|
result = mapper.interpolate(
|
||||||
result = mapper.interpolate(
|
template.dup,
|
||||||
template.dup,
|
template: true,
|
||||||
template: true,
|
user: true,
|
||||||
user: true,
|
wizard: true,
|
||||||
wizard: true,
|
value: true
|
||||||
value: true
|
)
|
||||||
)
|
expect(result).to eq(template_params_non_empty["step_1_field_3"])
|
||||||
expect(result).to eq("")
|
end
|
||||||
|
|
||||||
|
it "gives first non empty element from list when multiple non empty values present" do
|
||||||
|
template = <<-LIQUID.strip
|
||||||
|
{%- assign entry = "" | first_non_empty: step_1_field_1, step_1_field_2, step_1_field_3 -%}
|
||||||
|
{{ entry }}
|
||||||
|
LIQUID
|
||||||
|
mapper = create_template_mapper(template_params_multiple_non_empty, user1)
|
||||||
|
result = mapper.interpolate(
|
||||||
|
template.dup,
|
||||||
|
template: true,
|
||||||
|
user: true,
|
||||||
|
wizard: true,
|
||||||
|
value: true
|
||||||
|
)
|
||||||
|
expect(result).to eq(template_params_multiple_non_empty["step_1_field_2"])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "gives empty if all elements are empty" do
|
||||||
|
template = <<-LIQUID.strip
|
||||||
|
{%- assign entry = "" | first_non_empty: step_1_field_1, step_1_field_2, step_1_field_3 -%}
|
||||||
|
{%- if entry -%}
|
||||||
|
{{ entry }}
|
||||||
|
{%- endif -%}
|
||||||
|
LIQUID
|
||||||
|
mapper = create_template_mapper(template_params_empty, user1)
|
||||||
|
result = mapper.interpolate(
|
||||||
|
template.dup,
|
||||||
|
template: true,
|
||||||
|
user: true,
|
||||||
|
wizard: true,
|
||||||
|
value: true
|
||||||
|
)
|
||||||
|
expect(result).to eq("")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
125
spec/components/custom_wizard/pro_spec.rb
Normale Datei
125
spec/components/custom_wizard/pro_spec.rb
Normale Datei
|
@ -0,0 +1,125 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../../plugin_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::Pro 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)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns authorized and subscribed states" do
|
||||||
|
pro = described_class.new
|
||||||
|
expect(pro.authorized?).to eq(false)
|
||||||
|
expect(pro.subscribed?).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "subscription" do
|
||||||
|
before do
|
||||||
|
@pro = 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)
|
||||||
|
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)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "handles subscription http errors" do
|
||||||
|
stub_subscription_request(404, {})
|
||||||
|
expect(@pro.update_subscription).to eq(false)
|
||||||
|
expect(@pro.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)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "has class aliases" do
|
||||||
|
authenticate_pro
|
||||||
|
stub_subscription_request(200, valid_subscription)
|
||||||
|
expect(described_class.update_subscription).to eq(true)
|
||||||
|
expect(described_class.subscribed?).to eq(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "authentication" do
|
||||||
|
before do
|
||||||
|
@pro = 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)
|
||||||
|
|
||||||
|
parsed_query = Rack::Utils.parse_query uri.query
|
||||||
|
expect(parsed_query['public_key'].present?).to eq(true)
|
||||||
|
expect(parsed_query['nonce'].present?).to eq(true)
|
||||||
|
expect(parsed_query['client_id'].present?).to eq(true)
|
||||||
|
expect(parsed_query['auth_redirect'].present?).to eq(true)
|
||||||
|
expect(parsed_query['application_name']).to eq(SiteSetting.title)
|
||||||
|
expect(parsed_query['scopes']).to eq(@pro.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)
|
||||||
|
raw_payload = {
|
||||||
|
key: "12345",
|
||||||
|
nonce: keys.nonce,
|
||||||
|
push: false,
|
||||||
|
api: UserApiKeysController::AUTH_API_VERSION
|
||||||
|
}.to_json
|
||||||
|
public_key = OpenSSL::PKey::RSA.new(keys.pem)
|
||||||
|
Base64.encode64(public_key.public_encrypt(raw_payload))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "handles authentication response if request and response is valid" 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)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "discards authentication response if user who made request as not an admin" do
|
||||||
|
user.update!(admin: false)
|
||||||
|
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "destroys authentication" do
|
||||||
|
request_id = SecureRandom.hex(32)
|
||||||
|
payload = generate_payload(request_id, user.id)
|
||||||
|
@pro.authentication_response(request_id, payload)
|
||||||
|
|
||||||
|
expect(@pro.destroy_authentication).to eq(true)
|
||||||
|
expect(@pro.authorized?).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,21 +2,8 @@
|
||||||
require_relative '../../plugin_helper'
|
require_relative '../../plugin_helper'
|
||||||
|
|
||||||
describe CustomWizard::Step do
|
describe CustomWizard::Step do
|
||||||
let(:step_hash) do
|
let(:step_hash) { get_wizard_fixture("step/step") }
|
||||||
JSON.parse(
|
let(:field_hash) { get_wizard_fixture("field/field") }
|
||||||
File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/step/step.json"
|
|
||||||
).read
|
|
||||||
).with_indifferent_access
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:field_hash) do
|
|
||||||
JSON.parse(
|
|
||||||
File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/field/field.json"
|
|
||||||
).read
|
|
||||||
).with_indifferent_access
|
|
||||||
end
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@step = CustomWizard::Step.new(step_hash[:id])
|
@step = CustomWizard::Step.new(step_hash[:id])
|
||||||
|
|
|
@ -4,12 +4,7 @@ require_relative '../../plugin_helper'
|
||||||
describe CustomWizard::Submission do
|
describe CustomWizard::Submission do
|
||||||
fab!(:user) { Fabricate(:user) }
|
fab!(:user) { Fabricate(:user) }
|
||||||
fab!(:user2) { Fabricate(:user) }
|
fab!(:user2) { Fabricate(:user) }
|
||||||
|
let(:template_json) { get_wizard_fixture("wizard") }
|
||||||
let(:template_json) {
|
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read)
|
|
||||||
}
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
CustomWizard::Template.save(template_json, skip_jobs: true)
|
CustomWizard::Template.save(template_json, skip_jobs: true)
|
||||||
|
|
|
@ -3,17 +3,8 @@ require_relative '../../plugin_helper'
|
||||||
|
|
||||||
describe CustomWizard::Template do
|
describe CustomWizard::Template do
|
||||||
fab!(:user) { Fabricate(:user) }
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
let(:template_json) { get_wizard_fixture("wizard") }
|
||||||
let(:template_json) {
|
let(:permitted_json) { get_wizard_fixture("wizard/permitted") }
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read)
|
|
||||||
}
|
|
||||||
let(:permitted_json) {
|
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/permitted.json"
|
|
||||||
).read)
|
|
||||||
}
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
CustomWizard::Template.save(template_json, skip_jobs: true)
|
CustomWizard::Template.save(template_json, skip_jobs: true)
|
||||||
|
|
|
@ -3,12 +3,9 @@ require_relative '../../plugin_helper'
|
||||||
|
|
||||||
describe CustomWizard::TemplateValidator do
|
describe CustomWizard::TemplateValidator do
|
||||||
fab!(:user) { Fabricate(:user) }
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
let(:template) { get_wizard_fixture("wizard") }
|
||||||
let(:template) {
|
let(:create_category) { get_wizard_fixture("actions/create_category") }
|
||||||
JSON.parse(File.open(
|
let(:user_condition) { get_wizard_fixture("condition/user_condition") }
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read).with_indifferent_access
|
|
||||||
}
|
|
||||||
|
|
||||||
it "validates valid templates" do
|
it "validates valid templates" do
|
||||||
expect(
|
expect(
|
||||||
|
@ -45,4 +42,52 @@ describe CustomWizard::TemplateValidator do
|
||||||
CustomWizard::TemplateValidator.new(template).perform
|
CustomWizard::TemplateValidator.new(template).perform
|
||||||
).to eq(false)
|
).to eq(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "invalidates pro step attributes without a pro subscription" do
|
||||||
|
template[:steps][0][:condition] = user_condition['condition']
|
||||||
|
expect(
|
||||||
|
CustomWizard::TemplateValidator.new(template).perform
|
||||||
|
).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "invalidates pro field attributes without a pro subscription" do
|
||||||
|
template[:steps][0][:fields][0][:condition] = user_condition['condition']
|
||||||
|
expect(
|
||||||
|
CustomWizard::TemplateValidator.new(template).perform
|
||||||
|
).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "invalidates pro actions without a pro subscription" do
|
||||||
|
template[:actions] << create_category
|
||||||
|
expect(
|
||||||
|
CustomWizard::TemplateValidator.new(template).perform
|
||||||
|
).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with pro subscription" do
|
||||||
|
before do
|
||||||
|
enable_pro
|
||||||
|
end
|
||||||
|
|
||||||
|
it "validates pro step attributes" do
|
||||||
|
template[:steps][0][:condition] = user_condition['condition']
|
||||||
|
expect(
|
||||||
|
CustomWizard::TemplateValidator.new(template).perform
|
||||||
|
).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "validates pro field attributes" do
|
||||||
|
template[:steps][0][:fields][0][:condition] = user_condition['condition']
|
||||||
|
expect(
|
||||||
|
CustomWizard::TemplateValidator.new(template).perform
|
||||||
|
).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "validates pro actions" do
|
||||||
|
template[:actions] << create_category
|
||||||
|
expect(
|
||||||
|
CustomWizard::TemplateValidator.new(template).perform
|
||||||
|
).to eq(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,12 +3,7 @@ require_relative '../../plugin_helper'
|
||||||
|
|
||||||
describe CustomWizard::UpdateValidator do
|
describe CustomWizard::UpdateValidator do
|
||||||
fab!(:user) { Fabricate(:user) }
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
let(:template) { get_wizard_fixture("wizard") }
|
||||||
let(:template) {
|
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read).with_indifferent_access
|
|
||||||
}
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
CustomWizard::Template.save(template, skip_jobs: true)
|
CustomWizard::Template.save(template, skip_jobs: true)
|
||||||
|
|
|
@ -6,22 +6,8 @@ describe CustomWizard::Wizard do
|
||||||
fab!(:user) { Fabricate(:user) }
|
fab!(:user) { Fabricate(:user) }
|
||||||
fab!(:trusted_user) { Fabricate(:user, trust_level: TrustLevel[3]) }
|
fab!(:trusted_user) { Fabricate(:user, trust_level: TrustLevel[3]) }
|
||||||
fab!(:admin_user) { Fabricate(:user, admin: true) }
|
fab!(:admin_user) { Fabricate(:user, admin: true) }
|
||||||
|
let(:template_json) { get_wizard_fixture("wizard") }
|
||||||
let(:template_json) {
|
let(:permitted_json) { get_wizard_fixture("wizard/permitted") }
|
||||||
JSON.parse(
|
|
||||||
File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let(:permitted_json) {
|
|
||||||
JSON.parse(
|
|
||||||
File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/permitted.json"
|
|
||||||
).read
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
Group.refresh_automatic_group!(:trust_level_3)
|
Group.refresh_automatic_group!(:trust_level_3)
|
||||||
|
|
|
@ -9,11 +9,8 @@ describe "custom field extensions" do
|
||||||
fab!(:group) { Fabricate(:group) }
|
fab!(:group) { Fabricate(:group) }
|
||||||
fab!(:user) { Fabricate(:user) }
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
let(:custom_field_json) {
|
let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") }
|
||||||
JSON.parse(File.open(
|
let(:pro_custom_field_json) { get_wizard_fixture("custom_field/pro_custom_fields") }
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/custom_field/custom_fields.json"
|
|
||||||
).read)
|
|
||||||
}
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
custom_field_json['custom_fields'].each do |field_json|
|
custom_field_json['custom_fields'].each do |field_json|
|
||||||
|
@ -75,43 +72,54 @@ describe "custom field extensions" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "category" do
|
context "pro custom fields" do
|
||||||
it "registers category custom fields" do
|
before do
|
||||||
category
|
enable_pro
|
||||||
expect(Category.get_custom_field_type("category_field_1")).to eq(:json)
|
|
||||||
|
pro_custom_field_json['custom_fields'].each do |field_json|
|
||||||
|
custom_field = CustomWizard::CustomField.new(nil, field_json)
|
||||||
|
custom_field.save
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "adds category custom fields to the basic category serializer" do
|
context "category" do
|
||||||
category.custom_fields["category_field_1"] = { a: 1, b: 2 }.to_json
|
it "registers" do
|
||||||
category.save_custom_fields(true)
|
category
|
||||||
|
expect(Category.get_custom_field_type("category_field_1")).to eq(:json)
|
||||||
|
end
|
||||||
|
|
||||||
serializer = BasicCategorySerializer.new(
|
it "adds custom fields to the basic category serializer" do
|
||||||
category,
|
category.custom_fields["category_field_1"] = { a: 1, b: 2 }.to_json
|
||||||
scope: Guardian.new(user),
|
category.save_custom_fields(true)
|
||||||
root: false
|
|
||||||
).as_json
|
|
||||||
|
|
||||||
expect(serializer[:category_field_1]).to eq({ a: 1, b: 2 }.to_json)
|
serializer = BasicCategorySerializer.new(
|
||||||
end
|
category,
|
||||||
end
|
scope: Guardian.new(user),
|
||||||
|
root: false
|
||||||
|
).as_json
|
||||||
|
|
||||||
context "group" do
|
expect(serializer[:category_field_1]).to eq({ a: 1, b: 2 }.to_json)
|
||||||
it "registers group custom fields" do
|
end
|
||||||
group
|
|
||||||
expect(Group.get_custom_field_type("group_field_1")).to eq(:string)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "adds group custom fields to the basic group serializer" do
|
context "group" do
|
||||||
group.custom_fields["group_field_1"] = "Hello"
|
it "registers" do
|
||||||
group.save_custom_fields(true)
|
group
|
||||||
|
expect(Group.get_custom_field_type("group_field_1")).to eq(:string)
|
||||||
|
end
|
||||||
|
|
||||||
serializer = BasicGroupSerializer.new(
|
it "adds custom fields to the basic group serializer" do
|
||||||
group,
|
group.custom_fields["group_field_1"] = "Hello"
|
||||||
scope: Guardian.new(user),
|
group.save_custom_fields(true)
|
||||||
root: false
|
|
||||||
).as_json
|
|
||||||
|
|
||||||
expect(serializer[:group_field_1]).to eq("Hello")
|
serializer = BasicGroupSerializer.new(
|
||||||
|
group,
|
||||||
|
scope: Guardian.new(user),
|
||||||
|
root: false
|
||||||
|
).as_json
|
||||||
|
|
||||||
|
expect(serializer[:group_field_1]).to eq("Hello")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,18 +4,8 @@ require_relative '../plugin_helper'
|
||||||
describe ExtraLocalesControllerCustomWizard, type: :request do
|
describe ExtraLocalesControllerCustomWizard, type: :request do
|
||||||
let(:new_user) { Fabricate(:user, trust_level: TrustLevel[0]) }
|
let(:new_user) { Fabricate(:user, trust_level: TrustLevel[0]) }
|
||||||
let(:staff_user) { Fabricate(:moderator) }
|
let(:staff_user) { Fabricate(:moderator) }
|
||||||
|
let(:template) { get_wizard_fixture("wizard") }
|
||||||
let(:template) {
|
let(:permitted) { get_wizard_fixture("wizard/permitted") }
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read)
|
|
||||||
}
|
|
||||||
|
|
||||||
let(:permitted) {
|
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/permitted.json"
|
|
||||||
).read)
|
|
||||||
}
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
CustomWizard::Template.save(template, skip_jobs: true)
|
CustomWizard::Template.save(template, skip_jobs: true)
|
||||||
|
|
|
@ -4,12 +4,7 @@ require_relative '../plugin_helper'
|
||||||
describe InvitesControllerCustomWizard, type: :request do
|
describe InvitesControllerCustomWizard, type: :request do
|
||||||
fab!(:topic) { Fabricate(:topic) }
|
fab!(:topic) { Fabricate(:topic) }
|
||||||
let(:invite) { Invite.generate(topic.user, email: "angus@mcleod.org", topic: topic) }
|
let(:invite) { Invite.generate(topic.user, email: "angus@mcleod.org", topic: topic) }
|
||||||
|
let(:template) { get_wizard_fixture("wizard") }
|
||||||
let(:template) do
|
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read)
|
|
||||||
end
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@controller = InvitesController.new
|
@controller = InvitesController.new
|
||||||
|
|
|
@ -2,11 +2,7 @@
|
||||||
require_relative '../plugin_helper'
|
require_relative '../plugin_helper'
|
||||||
|
|
||||||
describe CustomWizardUsersController, type: :request do
|
describe CustomWizardUsersController, type: :request do
|
||||||
let(:template) do
|
let(:template) { get_wizard_fixture("wizard") }
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read)
|
|
||||||
end
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@controller = UsersController.new
|
@controller = UsersController.new
|
||||||
|
|
13
spec/fixtures/actions/add_to_group.json
gevendort
Normale Datei
13
spec/fixtures/actions/add_to_group.json
gevendort
Normale Datei
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"id": "action_6",
|
||||||
|
"run_after": "step_1",
|
||||||
|
"type": "add_to_group",
|
||||||
|
"group": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "action_9",
|
||||||
|
"output_type": "wizard_action",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
51
spec/fixtures/actions/create_category.json
gevendort
Normale Datei
51
spec/fixtures/actions/create_category.json
gevendort
Normale Datei
|
@ -0,0 +1,51 @@
|
||||||
|
{
|
||||||
|
"id": "action_8",
|
||||||
|
"run_after": "step_1",
|
||||||
|
"type": "create_category",
|
||||||
|
"custom_fields": [
|
||||||
|
{
|
||||||
|
"type": "association",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "category_custom_field",
|
||||||
|
"key_type": "text",
|
||||||
|
"value": "CC Val",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "association"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "step_1_field_1",
|
||||||
|
"output_type": "wizard_field",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"slug": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "step_1_field_1",
|
||||||
|
"output_type": "wizard_field",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"type": "association",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "action_9",
|
||||||
|
"key_type": "wizard_action",
|
||||||
|
"value": "2",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "association"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
104
spec/fixtures/actions/create_group.json
gevendort
Normale Datei
104
spec/fixtures/actions/create_group.json
gevendort
Normale Datei
|
@ -0,0 +1,104 @@
|
||||||
|
{
|
||||||
|
"id": "action_9",
|
||||||
|
"run_after": "step_1",
|
||||||
|
"type": "create_group",
|
||||||
|
"title": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "New Group Member",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"custom_fields": [
|
||||||
|
{
|
||||||
|
"type": "association",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "group_custom_field",
|
||||||
|
"key_type": "text",
|
||||||
|
"value": "step_3_field_1",
|
||||||
|
"value_type": "wizard_field",
|
||||||
|
"connector": "association"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "step_1_field_1",
|
||||||
|
"output_type": "wizard_field",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"full_name": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "step_1_field_1",
|
||||||
|
"output_type": "wizard_field",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"usernames": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "user",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": [
|
||||||
|
"angus1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"owner_usernames": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "user",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": [
|
||||||
|
"angus"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"grant_trust_level": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "3",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mentionable_level": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "1",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"messageable_level": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "2",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"visibility_level": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "3",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"members_visibility_level": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "99",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
25
spec/fixtures/actions/send_message.json
gevendort
Normale Datei
25
spec/fixtures/actions/send_message.json
gevendort
Normale Datei
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"id": "action_2",
|
||||||
|
"run_after": "step_2",
|
||||||
|
"type": "send_message",
|
||||||
|
"post_builder": true,
|
||||||
|
"post_template": "I will interpolate some wizard fields w{step_1_field_1} w{step_1_field_2}",
|
||||||
|
"title": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "Message title",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"recipient": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "user",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": [
|
||||||
|
"angus1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
28
spec/fixtures/actions/send_message_multi.json
gevendort
Normale Datei
28
spec/fixtures/actions/send_message_multi.json
gevendort
Normale Datei
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"id": "action_11",
|
||||||
|
"run_after": "step_2",
|
||||||
|
"type": "send_message",
|
||||||
|
"post_builder": true,
|
||||||
|
"post_template": "I will interpolate some wizard fields w{step_1_field_1} w{step_1_field_2}",
|
||||||
|
"title": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "Multiple Recipients title",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"recipient": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "user",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": [
|
||||||
|
"angus1",
|
||||||
|
"faiz",
|
||||||
|
"cool_group",
|
||||||
|
"cool_group_1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
16
spec/fixtures/custom_field/custom_fields.json
gevendort
16
spec/fixtures/custom_field/custom_fields.json
gevendort
|
@ -16,22 +16,6 @@
|
||||||
"serializers": [
|
"serializers": [
|
||||||
"post"
|
"post"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"klass": "category",
|
|
||||||
"name": "category_field_1",
|
|
||||||
"type": "json",
|
|
||||||
"serializers": [
|
|
||||||
"basic_category"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"klass": "group",
|
|
||||||
"name": "group_field_1",
|
|
||||||
"type": "string",
|
|
||||||
"serializers": [
|
|
||||||
"basic_group"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
28
spec/fixtures/custom_field/pro_custom_fields.json
gevendort
Normale Datei
28
spec/fixtures/custom_field/pro_custom_fields.json
gevendort
Normale Datei
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"custom_fields": [
|
||||||
|
{
|
||||||
|
"klass": "topic",
|
||||||
|
"name": "topic_field_2",
|
||||||
|
"type": "json",
|
||||||
|
"serializers": [
|
||||||
|
"topic_view"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"klass": "category",
|
||||||
|
"name": "category_field_1",
|
||||||
|
"type": "json",
|
||||||
|
"serializers": [
|
||||||
|
"basic_category"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"klass": "group",
|
||||||
|
"name": "group_field_1",
|
||||||
|
"type": "string",
|
||||||
|
"serializers": [
|
||||||
|
"basic_group"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
285
spec/fixtures/wizard.json
gevendort
285
spec/fixtures/wizard.json
gevendort
|
@ -163,197 +163,6 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"actions": [
|
"actions": [
|
||||||
{
|
|
||||||
"id": "action_9",
|
|
||||||
"run_after": "step_1",
|
|
||||||
"type": "create_group",
|
|
||||||
"title": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output": "New Group Member",
|
|
||||||
"output_type": "text",
|
|
||||||
"output_connector": "set"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"custom_fields": [
|
|
||||||
{
|
|
||||||
"type": "association",
|
|
||||||
"pairs": [
|
|
||||||
{
|
|
||||||
"index": 0,
|
|
||||||
"key": "group_custom_field",
|
|
||||||
"key_type": "text",
|
|
||||||
"value": "step_3_field_1",
|
|
||||||
"value_type": "wizard_field",
|
|
||||||
"connector": "association"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output": "step_1_field_1",
|
|
||||||
"output_type": "wizard_field",
|
|
||||||
"output_connector": "set"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"full_name": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output": "step_1_field_1",
|
|
||||||
"output_type": "wizard_field",
|
|
||||||
"output_connector": "set"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"usernames": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output_type": "user",
|
|
||||||
"output_connector": "set",
|
|
||||||
"output": [
|
|
||||||
"angus1"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"owner_usernames": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output_type": "user",
|
|
||||||
"output_connector": "set",
|
|
||||||
"output": [
|
|
||||||
"angus"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"grant_trust_level": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output": "3",
|
|
||||||
"output_type": "text",
|
|
||||||
"output_connector": "set"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"mentionable_level": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output": "1",
|
|
||||||
"output_type": "text",
|
|
||||||
"output_connector": "set"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"messageable_level": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output": "2",
|
|
||||||
"output_type": "text",
|
|
||||||
"output_connector": "set"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"visibility_level": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output": "3",
|
|
||||||
"output_type": "text",
|
|
||||||
"output_connector": "set"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"members_visibility_level": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output": "99",
|
|
||||||
"output_type": "text",
|
|
||||||
"output_connector": "set"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "action_6",
|
|
||||||
"run_after": "step_1",
|
|
||||||
"type": "add_to_group",
|
|
||||||
"group": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output": "action_9",
|
|
||||||
"output_type": "wizard_action",
|
|
||||||
"output_connector": "set"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "action_8",
|
|
||||||
"run_after": "step_1",
|
|
||||||
"type": "create_category",
|
|
||||||
"custom_fields": [
|
|
||||||
{
|
|
||||||
"type": "association",
|
|
||||||
"pairs": [
|
|
||||||
{
|
|
||||||
"index": 0,
|
|
||||||
"key": "category_custom_field",
|
|
||||||
"key_type": "text",
|
|
||||||
"value": "CC Val",
|
|
||||||
"value_type": "text",
|
|
||||||
"connector": "association"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output": "step_1_field_1",
|
|
||||||
"output_type": "wizard_field",
|
|
||||||
"output_connector": "set"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"slug": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output": "step_1_field_1",
|
|
||||||
"output_type": "wizard_field",
|
|
||||||
"output_connector": "set"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"permissions": [
|
|
||||||
{
|
|
||||||
"type": "association",
|
|
||||||
"pairs": [
|
|
||||||
{
|
|
||||||
"index": 0,
|
|
||||||
"key": "action_9",
|
|
||||||
"key_type": "wizard_action",
|
|
||||||
"value": "2",
|
|
||||||
"value_type": "text",
|
|
||||||
"connector": "association"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "action_5",
|
|
||||||
"run_after": "step_1",
|
|
||||||
"type": "watch_categories",
|
|
||||||
"notification_level": "tracking",
|
|
||||||
"wizard_user": true,
|
|
||||||
"categories": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output": "action_8",
|
|
||||||
"output_type": "wizard_action",
|
|
||||||
"output_connector": "set"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"mute_remainder": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output": "true",
|
|
||||||
"output_type": "text",
|
|
||||||
"output_connector": "set"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "action_1",
|
"id": "action_1",
|
||||||
"run_after": "step_3",
|
"run_after": "step_3",
|
||||||
|
@ -442,6 +251,29 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "action_5",
|
||||||
|
"run_after": "step_1",
|
||||||
|
"type": "watch_categories",
|
||||||
|
"notification_level": "tracking",
|
||||||
|
"wizard_user": true,
|
||||||
|
"categories": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "action_8",
|
||||||
|
"output_type": "wizard_action",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mute_remainder": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "true",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "action_4",
|
"id": "action_4",
|
||||||
"run_after": "step_2",
|
"run_after": "step_2",
|
||||||
|
@ -462,59 +294,6 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "action_2",
|
|
||||||
"run_after": "step_2",
|
|
||||||
"type": "send_message",
|
|
||||||
"post_builder": true,
|
|
||||||
"post_template": "I will interpolate some wizard fields w{step_1_field_1} w{step_1_field_2}",
|
|
||||||
"title": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output": "Message title",
|
|
||||||
"output_type": "text",
|
|
||||||
"output_connector": "set"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"recipient": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output_type": "user",
|
|
||||||
"output_connector": "set",
|
|
||||||
"output": [
|
|
||||||
"angus1"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "action_11",
|
|
||||||
"run_after": "step_2",
|
|
||||||
"type": "send_message",
|
|
||||||
"post_builder": true,
|
|
||||||
"post_template": "I will interpolate some wizard fields w{step_1_field_1} w{step_1_field_2}",
|
|
||||||
"title": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output": "Multiple Recipients title",
|
|
||||||
"output_type": "text",
|
|
||||||
"output_connector": "set"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"recipient": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output_type": "user",
|
|
||||||
"output_connector": "set",
|
|
||||||
"output": [
|
|
||||||
"angus1",
|
|
||||||
"faiz",
|
|
||||||
"cool_group",
|
|
||||||
"cool_group_1"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "action_3",
|
"id": "action_3",
|
||||||
"run_after": "step_2",
|
"run_after": "step_2",
|
||||||
|
@ -529,24 +308,6 @@
|
||||||
"output_connector": "set"
|
"output_connector": "set"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"category": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output": "action_8",
|
|
||||||
"output_type": "wizard_action",
|
|
||||||
"output_connector": "set",
|
|
||||||
"pairs": [
|
|
||||||
{
|
|
||||||
"index": 0,
|
|
||||||
"key": "step_2_field_5",
|
|
||||||
"key_type": "wizard_field",
|
|
||||||
"value": "true",
|
|
||||||
"value_type": "text",
|
|
||||||
"connector": "is"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"tags": [
|
"tags": [
|
||||||
{
|
{
|
||||||
"type": "assignment",
|
"type": "assignment",
|
||||||
|
|
|
@ -7,11 +7,7 @@ describe Jobs::SetAfterTimeWizard do
|
||||||
fab!(:user2) { Fabricate(:user) }
|
fab!(:user2) { Fabricate(:user) }
|
||||||
fab!(:user3) { Fabricate(:user) }
|
fab!(:user3) { Fabricate(:user) }
|
||||||
|
|
||||||
let(:template) {
|
let(:template) { get_wizard_fixture("wizard") }
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read).with_indifferent_access
|
|
||||||
}
|
|
||||||
|
|
||||||
it "sets wizard redirect for all users " do
|
it "sets wizard redirect for all users " do
|
||||||
after_time_template = template.dup
|
after_time_template = template.dup
|
||||||
|
|
11
spec/jobs/update_pro_subscription_spec.rb
Normale Datei
11
spec/jobs/update_pro_subscription_spec.rb
Normale Datei
|
@ -0,0 +1,11 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../plugin_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::UpdateProSubscription do
|
||||||
|
it "updates the pro subscription" do
|
||||||
|
stub_subscription_request(200, valid_subscription)
|
||||||
|
described_class.new.execute
|
||||||
|
expect(CustomWizard::Pro.subscribed?).to eq(true)
|
||||||
|
end
|
||||||
|
end
|
|
@ -15,3 +15,44 @@ require 'oj'
|
||||||
Oj.default_options = Oj.default_options.merge(cache_str: -1)
|
Oj.default_options = Oj.default_options.merge(cache_str: -1)
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
|
def get_wizard_fixture(path)
|
||||||
|
JSON.parse(
|
||||||
|
File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/#{path}.json"
|
||||||
|
).read
|
||||||
|
).with_indifferent_access
|
||||||
|
end
|
||||||
|
|
||||||
|
def authenticate_pro
|
||||||
|
CustomWizard::ProAuthentication.any_instance.stubs(:active?).returns(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def enable_pro
|
||||||
|
CustomWizard::Pro.any_instance.stubs(:subscribed?).returns(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def disable_pro
|
||||||
|
CustomWizard::Pro.any_instance.stubs(:subscribed?).returns(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid_subscription
|
||||||
|
{
|
||||||
|
product_id: "prod_CBTNpi3fqWWkq0",
|
||||||
|
price_id: "price_id",
|
||||||
|
price_nickname: "business"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def invalid_subscription
|
||||||
|
{
|
||||||
|
product_id: "prod_CBTNpi3fqWWkq0",
|
||||||
|
price_id: "price_id"
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
end
|
||||||
|
|
|
@ -3,12 +3,7 @@ require_relative '../../../plugin_helper'
|
||||||
|
|
||||||
describe CustomWizard::AdminCustomFieldsController do
|
describe CustomWizard::AdminCustomFieldsController do
|
||||||
fab!(:admin_user) { Fabricate(:user, admin: true) }
|
fab!(:admin_user) { Fabricate(:user, admin: true) }
|
||||||
|
let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") }
|
||||||
let(:custom_field_json) {
|
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/custom_field/custom_fields.json"
|
|
||||||
).read)
|
|
||||||
}
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
custom_field_json['custom_fields'].each do |field_json|
|
custom_field_json['custom_fields'].each do |field_json|
|
||||||
|
@ -19,7 +14,7 @@ describe CustomWizard::AdminCustomFieldsController do
|
||||||
|
|
||||||
it "returns the full list of custom fields" do
|
it "returns the full list of custom fields" do
|
||||||
get "/admin/wizards/custom-fields.json"
|
get "/admin/wizards/custom-fields.json"
|
||||||
expect(response.parsed_body.length).to eq(15)
|
expect(response.parsed_body["custom_fields"].length).to be > 12
|
||||||
end
|
end
|
||||||
|
|
||||||
it "saves custom fields" do
|
it "saves custom fields" do
|
||||||
|
|
|
@ -3,12 +3,7 @@ require_relative '../../../plugin_helper'
|
||||||
|
|
||||||
describe CustomWizard::AdminManagerController do
|
describe CustomWizard::AdminManagerController do
|
||||||
fab!(:admin_user) { Fabricate(:user, admin: true) }
|
fab!(:admin_user) { Fabricate(:user, admin: true) }
|
||||||
|
let(:template) { get_wizard_fixture("wizard") }
|
||||||
let(:template) {
|
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read)
|
|
||||||
}
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
sign_in(admin_user)
|
sign_in(admin_user)
|
||||||
|
|
71
spec/requests/custom_wizard/admin/pro_controller_spec.rb
Normale Datei
71
spec/requests/custom_wizard/admin/pro_controller_spec.rb
Normale Datei
|
@ -0,0 +1,71 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
require_relative '../../../plugin_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::AdminProController 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)
|
||||||
|
raw_payload = {
|
||||||
|
key: "12345",
|
||||||
|
nonce: keys.nonce,
|
||||||
|
push: false,
|
||||||
|
api: UserApiKeysController::AUTH_API_VERSION
|
||||||
|
}.to_json
|
||||||
|
public_key = OpenSSL::PKey::RSA.new(keys.pem)
|
||||||
|
Base64.encode64(public_key.public_encrypt(raw_payload))
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
@pro = CustomWizard::Pro.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)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "#authorize" do
|
||||||
|
get "/admin/wizards/pro/authorize"
|
||||||
|
expect(response.status).to eq(302)
|
||||||
|
expect(cookies[:user_api_request_id].present?).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "#destroy_authentication" do
|
||||||
|
request_id = SecureRandom.hex(32)
|
||||||
|
payload = generate_payload(request_id, admin_user.id)
|
||||||
|
@pro.authentication_response(request_id, payload)
|
||||||
|
|
||||||
|
delete "/admin/wizards/pro/authorize.json"
|
||||||
|
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(CustomWizard::Pro.authorized?).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "subscription" do
|
||||||
|
before do
|
||||||
|
stub_subscription_request(200, valid_subscription)
|
||||||
|
end
|
||||||
|
|
||||||
|
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 }
|
||||||
|
|
||||||
|
expect(response).to redirect_to("/admin/wizards/pro")
|
||||||
|
expect(CustomWizard::Pro.subscribed?).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "updates the subscription" do
|
||||||
|
authenticate_pro
|
||||||
|
post "/admin/wizards/pro/subscription.json"
|
||||||
|
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(CustomWizard::Pro.subscribed?).to eq(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -7,12 +7,7 @@ describe CustomWizard::AdminSubmissionsController do
|
||||||
fab!(:user2) { Fabricate(:user) }
|
fab!(:user2) { Fabricate(:user) }
|
||||||
fab!(:user3) { Fabricate(:user) }
|
fab!(:user3) { Fabricate(:user) }
|
||||||
|
|
||||||
let(:template) {
|
let(:template) { get_wizard_fixture("wizard") }
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read)
|
|
||||||
}
|
|
||||||
|
|
||||||
let(:template_2) {
|
let(:template_2) {
|
||||||
temp = template.dup
|
temp = template.dup
|
||||||
temp["id"] = "super_mega_fun_wizard_2"
|
temp["id"] = "super_mega_fun_wizard_2"
|
||||||
|
|
|
@ -5,12 +5,7 @@ describe CustomWizard::AdminWizardController do
|
||||||
fab!(:admin_user) { Fabricate(:user, admin: true) }
|
fab!(:admin_user) { Fabricate(:user, admin: true) }
|
||||||
fab!(:user1) { Fabricate(:user) }
|
fab!(:user1) { Fabricate(:user) }
|
||||||
fab!(:user2) { Fabricate(:user) }
|
fab!(:user2) { Fabricate(:user) }
|
||||||
|
let(:template) { get_wizard_fixture("wizard") }
|
||||||
let(:template) {
|
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read)
|
|
||||||
}
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
CustomWizard::Template.save(template, skip_jobs: true)
|
CustomWizard::Template.save(template, skip_jobs: true)
|
||||||
|
|
|
@ -2,21 +2,11 @@
|
||||||
require_relative '../../plugin_helper'
|
require_relative '../../plugin_helper'
|
||||||
|
|
||||||
describe ApplicationController do
|
describe ApplicationController do
|
||||||
fab!(:user) {
|
fab!(:user) { Fabricate(:user, username: 'angus', email: "angus@email.com", trust_level: TrustLevel[3]) }
|
||||||
Fabricate(
|
let(:wizard_template) { get_wizard_fixture("wizard") }
|
||||||
:user,
|
|
||||||
username: 'angus',
|
|
||||||
email: "angus@email.com",
|
|
||||||
trust_level: TrustLevel[3]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
CustomWizard::Template.save(
|
CustomWizard::Template.save(wizard_template, skip_jobs: true)
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read),
|
|
||||||
skip_jobs: true)
|
|
||||||
@template = CustomWizard::Template.find('super_mega_fun_wizard')
|
@template = CustomWizard::Template.find('super_mega_fun_wizard')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,8 @@ describe "custom field extensions" do
|
||||||
let!(:category) { Fabricate(:category) }
|
let!(:category) { Fabricate(:category) }
|
||||||
let!(:user) { Fabricate(:user) }
|
let!(:user) { Fabricate(:user) }
|
||||||
let!(:group) { Fabricate(:group, users: [user]) }
|
let!(:group) { Fabricate(:group, users: [user]) }
|
||||||
|
let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") }
|
||||||
let(:custom_field_json) {
|
let(:pro_custom_field_json) { get_wizard_fixture("custom_field/pro_custom_fields") }
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/custom_field/custom_fields.json"
|
|
||||||
).read)
|
|
||||||
}
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
custom_field_json['custom_fields'].each do |field_json|
|
custom_field_json['custom_fields'].each do |field_json|
|
||||||
|
@ -32,27 +28,6 @@ describe "custom field extensions" do
|
||||||
expect(response.parsed_body["topic_field_1"]).to eq(true)
|
expect(response.parsed_body["topic_field_1"]).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "adds category custom fields to the show categories response" do
|
|
||||||
category.custom_fields["category_field_1"] = { a: 1, b: 2 }
|
|
||||||
category.save_custom_fields(true)
|
|
||||||
|
|
||||||
get "/c/#{category.id}/show.json"
|
|
||||||
|
|
||||||
expect(response.status).to eq(200)
|
|
||||||
expect(response.parsed_body["category"]["category_field_1"]).to eq({ a: 1, b: 2 }.as_json)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "adds group custom fields to the show group response" do
|
|
||||||
group.custom_fields["group_field_1"] = "Group cf entry"
|
|
||||||
group.save_custom_fields(true)
|
|
||||||
|
|
||||||
sign_in(user)
|
|
||||||
get "/groups/#{group.name}.json"
|
|
||||||
|
|
||||||
expect(response.status).to eq(200)
|
|
||||||
expect(response.parsed_body['group']['group_field_1']).to eq("Group cf entry")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "adds post custom fields to the show post response" do
|
it "adds post custom fields to the show post response" do
|
||||||
post.custom_fields["post_field_1"] = 7
|
post.custom_fields["post_field_1"] = 7
|
||||||
post.save_custom_fields(true)
|
post.save_custom_fields(true)
|
||||||
|
@ -63,32 +38,64 @@ describe "custom field extensions" do
|
||||||
expect(response.parsed_body['post_field_1']).to eq(7)
|
expect(response.parsed_body['post_field_1']).to eq(7)
|
||||||
end
|
end
|
||||||
|
|
||||||
context "preloaded" do
|
context "with a pro subscription" do
|
||||||
it "preloads category custom fields on site categories" do
|
before do
|
||||||
Site.preloaded_category_custom_fields << "other_field"
|
enable_pro
|
||||||
|
|
||||||
|
pro_custom_field_json['custom_fields'].each do |field_json|
|
||||||
|
custom_field = CustomWizard::CustomField.new(nil, field_json)
|
||||||
|
custom_field.save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "adds category custom fields to the show categories response" do
|
||||||
category.custom_fields["category_field_1"] = { a: 1, b: 2 }
|
category.custom_fields["category_field_1"] = { a: 1, b: 2 }
|
||||||
category.save_custom_fields(true)
|
category.save_custom_fields(true)
|
||||||
|
|
||||||
get "/site.json"
|
get "/c/#{category.id}/show.json"
|
||||||
expect(response.status).to eq(200)
|
|
||||||
|
|
||||||
site_category = response.parsed_body['categories'].select { |c| c['id'] == category.id }.first
|
expect(response.status).to eq(200)
|
||||||
expect(site_category["category_field_1"]).to eq({ a: 1, b: 2 }.as_json)
|
expect(response.parsed_body["category"]["category_field_1"]).to eq({ a: 1, b: 2 }.as_json)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "preloads group custom fields on group index" do
|
it "adds group custom fields to the show group response" do
|
||||||
Group.preloaded_custom_field_names << "other_field"
|
|
||||||
|
|
||||||
group = Fabricate(:group)
|
|
||||||
group.custom_fields["group_field_1"] = "Group cf entry"
|
group.custom_fields["group_field_1"] = "Group cf entry"
|
||||||
group.save_custom_fields(true)
|
group.save_custom_fields(true)
|
||||||
|
|
||||||
get "/groups.json"
|
sign_in(user)
|
||||||
expect(response.status).to eq(200)
|
get "/groups/#{group.name}.json"
|
||||||
|
|
||||||
group = response.parsed_body['groups'].select { |g| g['id'] == group.id }.first
|
expect(response.status).to eq(200)
|
||||||
expect(group['group_field_1']).to eq("Group cf entry")
|
expect(response.parsed_body['group']['group_field_1']).to eq("Group cf entry")
|
||||||
|
end
|
||||||
|
|
||||||
|
context "preloaded" do
|
||||||
|
it "preloads category custom fields on site categories" do
|
||||||
|
Site.preloaded_category_custom_fields << "other_field"
|
||||||
|
|
||||||
|
category.custom_fields["category_field_1"] = { a: 1, b: 2 }
|
||||||
|
category.save_custom_fields(true)
|
||||||
|
|
||||||
|
get "/site.json"
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
|
||||||
|
site_category = response.parsed_body['categories'].select { |c| c['id'] == category.id }.first
|
||||||
|
expect(site_category["category_field_1"]).to eq({ a: 1, b: 2 }.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "preloads group custom fields on group index" do
|
||||||
|
Group.preloaded_custom_field_names << "other_field"
|
||||||
|
|
||||||
|
group = Fabricate(:group)
|
||||||
|
group.custom_fields["group_field_1"] = "Group cf entry"
|
||||||
|
group.save_custom_fields(true)
|
||||||
|
|
||||||
|
get "/groups.json"
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
|
||||||
|
group = response.parsed_body['groups'].select { |g| g['id'] == group.id }.first
|
||||||
|
expect(group['group_field_1']).to eq("Group cf entry")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,55 +2,12 @@
|
||||||
require_relative '../../plugin_helper'
|
require_relative '../../plugin_helper'
|
||||||
|
|
||||||
describe CustomWizard::StepsController do
|
describe CustomWizard::StepsController do
|
||||||
fab!(:user) {
|
fab!(:user) { Fabricate(:user, username: 'angus', email: "angus@email.com", trust_level: TrustLevel[3]) }
|
||||||
Fabricate(
|
fab!(:user2) { Fabricate(:user, username: 'bob', email: "bob@email.com", trust_level: TrustLevel[2]) }
|
||||||
:user,
|
let(:wizard_template) { get_wizard_fixture("wizard") }
|
||||||
username: 'angus',
|
let(:wizard_field_condition_template) { get_wizard_fixture("condition/wizard_field_condition") }
|
||||||
email: "angus@email.com",
|
let(:user_condition_template) { get_wizard_fixture("condition/user_condition") }
|
||||||
trust_level: TrustLevel[3]
|
let(:permitted_json) { get_wizard_fixture("wizard/permitted") }
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fab!(:user2) {
|
|
||||||
Fabricate(
|
|
||||||
:user,
|
|
||||||
username: 'bob',
|
|
||||||
email: "bob@email.com",
|
|
||||||
trust_level: TrustLevel[2]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let(:wizard_template) {
|
|
||||||
JSON.parse(
|
|
||||||
File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let(:wizard_field_condition_template) {
|
|
||||||
JSON.parse(
|
|
||||||
File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/condition/wizard_field_condition.json"
|
|
||||||
).read
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let(:user_condition_template) {
|
|
||||||
JSON.parse(
|
|
||||||
File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/condition/user_condition.json"
|
|
||||||
).read
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let(:permitted_json) {
|
|
||||||
JSON.parse(
|
|
||||||
File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/permitted.json"
|
|
||||||
).read
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
CustomWizard::Template.save(wizard_template, skip_jobs: true)
|
CustomWizard::Template.save(wizard_template, skip_jobs: true)
|
||||||
|
@ -90,17 +47,6 @@ describe CustomWizard::StepsController do
|
||||||
put '/w/super-mega-fun-wizard/steps/step_10.json'
|
put '/w/super-mega-fun-wizard/steps/step_10.json'
|
||||||
expect(response.status).to eq(400)
|
expect(response.status).to eq(400)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "works if the step has no fields" do
|
it "works if the step has no fields" do
|
||||||
|
@ -123,64 +69,40 @@ describe CustomWizard::StepsController do
|
||||||
expect(response.parsed_body['wizard']['start']).to eq("step_2")
|
expect(response.parsed_body['wizard']['start']).to eq("step_2")
|
||||||
end
|
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 "runs completion actions if user has completed wizard" do
|
it "runs completion actions if user has completed wizard" do
|
||||||
new_template = wizard_template.dup
|
new_template = wizard_template.dup
|
||||||
|
|
||||||
## route_to action
|
## route_to action
|
||||||
new_template['actions'].last['run_after'] = 'wizard_completion'
|
new_template['actions'].last['run_after'] = 'wizard_completion'
|
||||||
new_template['steps'][1]['condition'] = wizard_field_condition_template['condition']
|
|
||||||
new_template['steps'][2]['condition'] = wizard_field_condition_template['condition']
|
|
||||||
CustomWizard::Template.save(new_template, skip_jobs: true)
|
CustomWizard::Template.save(new_template, skip_jobs: true)
|
||||||
|
|
||||||
put '/w/super-mega-fun-wizard/steps/step_1.json', params: {
|
put '/w/super-mega-fun-wizard/steps/step_1.json'
|
||||||
fields: {
|
put '/w/super-mega-fun-wizard/steps/step_2.json'
|
||||||
step_1_field_1: "Condition wont pass"
|
put '/w/super-mega-fun-wizard/steps/step_3.json'
|
||||||
}
|
|
||||||
}
|
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response.parsed_body['redirect_on_complete']).to eq("https://google.com")
|
expect(response.parsed_body['redirect_on_complete']).to eq("https://google.com")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "saves results of completion actions if user has completed wizard" do
|
it "saves results of completion actions if user has completed wizard" do
|
||||||
new_template = wizard_template.dup
|
new_template = wizard_template.dup
|
||||||
|
|
||||||
## Create group action
|
|
||||||
new_template['actions'].first['run_after'] = 'wizard_completion'
|
new_template['actions'].first['run_after'] = 'wizard_completion'
|
||||||
new_template['steps'][1]['condition'] = wizard_field_condition_template['condition']
|
|
||||||
CustomWizard::Template.save(new_template, skip_jobs: true)
|
CustomWizard::Template.save(new_template, skip_jobs: true)
|
||||||
|
|
||||||
put '/w/super-mega-fun-wizard/steps/step_1.json', params: {
|
put '/w/super-mega-fun-wizard/steps/step_1.json', params: {
|
||||||
fields: {
|
fields: {
|
||||||
step_1_field_1: "My cool group"
|
step_1_field_1: "Topic title",
|
||||||
|
step_1_field_2: "Topic post"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect(response.status).to eq(200)
|
put '/w/super-mega-fun-wizard/steps/step_2.json'
|
||||||
|
|
||||||
put '/w/super-mega-fun-wizard/steps/step_3.json'
|
put '/w/super-mega-fun-wizard/steps/step_3.json'
|
||||||
expect(response.status).to eq(200)
|
|
||||||
|
|
||||||
wizard_id = response.parsed_body['wizard']['id']
|
wizard_id = response.parsed_body['wizard']['id']
|
||||||
wizard = CustomWizard::Wizard.create(wizard_id, user)
|
wizard = CustomWizard::Wizard.create(wizard_id, user)
|
||||||
|
|
||||||
group_name = wizard.submissions.first.fields['action_9']
|
topic_id = wizard.submissions.first.fields[new_template['actions'].first['id']]
|
||||||
group = Group.find_by(name: group_name)
|
topic = Topic.find(topic_id)
|
||||||
|
expect(topic.present?).to eq(true)
|
||||||
expect(group.present?).to eq(true)
|
|
||||||
expect(group.full_name).to eq("My cool group")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns a final step without conditions" do
|
it "returns a final step without conditions" do
|
||||||
|
@ -197,88 +119,119 @@ describe CustomWizard::StepsController do
|
||||||
expect(response.parsed_body['final']).to eq(true)
|
expect(response.parsed_body['final']).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns the correct final step when the conditional final step and last step are the same" do
|
context "pro" do
|
||||||
new_template = wizard_template.dup
|
before do
|
||||||
new_template['steps'][0]['condition'] = user_condition_template['condition']
|
enable_pro
|
||||||
new_template['steps'][2]['condition'] = wizard_field_condition_template['condition']
|
end
|
||||||
CustomWizard::Template.save(new_template, skip_jobs: true)
|
|
||||||
|
|
||||||
put '/w/super-mega-fun-wizard/steps/step_1.json', params: {
|
it "raises an error when user cant see the step due to conditions" do
|
||||||
fields: {
|
sign_in(user2)
|
||||||
step_1_field_1: "Condition will pass"
|
|
||||||
|
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.status).to eq(200)
|
expect(response.parsed_body['wizard']['start']).to eq("step_3")
|
||||||
expect(response.parsed_body['final']).to eq(false)
|
end
|
||||||
|
|
||||||
put '/w/super-mega-fun-wizard/steps/step_2.json'
|
it "returns the correct final step when the conditional final step and last step are the same" do
|
||||||
expect(response.status).to eq(200)
|
new_template = wizard_template.dup
|
||||||
expect(response.parsed_body['final']).to eq(false)
|
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)
|
||||||
|
|
||||||
put '/w/super-mega-fun-wizard/steps/step_3.json'
|
put '/w/super-mega-fun-wizard/steps/step_1.json', params: {
|
||||||
expect(response.status).to eq(200)
|
fields: {
|
||||||
expect(response.parsed_body['final']).to eq(true)
|
step_1_field_1: "Condition will pass"
|
||||||
end
|
}
|
||||||
|
|
||||||
it "returns the correct final step when the conditional final step and last step are different" do
|
|
||||||
new_template = wizard_template.dup
|
|
||||||
new_template['steps'][2]['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 will not pass"
|
|
||||||
}
|
}
|
||||||
}
|
expect(response.status).to eq(200)
|
||||||
expect(response.status).to eq(200)
|
expect(response.parsed_body['final']).to eq(false)
|
||||||
expect(response.parsed_body['final']).to eq(false)
|
|
||||||
|
|
||||||
put '/w/super-mega-fun-wizard/steps/step_2.json'
|
put '/w/super-mega-fun-wizard/steps/step_2.json'
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response.parsed_body['final']).to eq(true)
|
expect(response.parsed_body['final']).to eq(false)
|
||||||
end
|
|
||||||
|
|
||||||
it "returns the correct final step when the conditional final step is determined in the same action" do
|
put '/w/super-mega-fun-wizard/steps/step_3.json'
|
||||||
new_template = wizard_template.dup
|
expect(response.status).to eq(200)
|
||||||
new_template['steps'][1]['condition'] = wizard_field_condition_template['condition']
|
expect(response.parsed_body['final']).to eq(true)
|
||||||
new_template['steps'][2]['condition'] = wizard_field_condition_template['condition']
|
end
|
||||||
CustomWizard::Template.save(new_template, skip_jobs: true)
|
|
||||||
|
|
||||||
put '/w/super-mega-fun-wizard/steps/step_1.json', params: {
|
it "returns the correct final step when the conditional final step and last step are different" do
|
||||||
fields: {
|
new_template = wizard_template.dup
|
||||||
step_1_field_1: "Condition will not pass"
|
new_template['steps'][2]['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 will not pass"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
expect(response.status).to eq(200)
|
||||||
expect(response.status).to eq(200)
|
expect(response.parsed_body['final']).to eq(false)
|
||||||
expect(response.parsed_body['final']).to eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "excludes the non-included conditional fields from the submissions" do
|
put '/w/super-mega-fun-wizard/steps/step_2.json'
|
||||||
new_template = wizard_template.dup
|
expect(response.status).to eq(200)
|
||||||
new_template['steps'][1]['fields'][0]['condition'] = wizard_field_condition_template['condition']
|
expect(response.parsed_body['final']).to eq(true)
|
||||||
CustomWizard::Template.save(new_template, skip_jobs: true)
|
end
|
||||||
|
|
||||||
put '/w/super-mega-fun-wizard/steps/step_1.json', params: {
|
it "returns the correct final step when the conditional final step is determined in the same action" do
|
||||||
fields: {
|
new_template = wizard_template.dup
|
||||||
step_1_field_1: "Condition will pass"
|
new_template['steps'][1]['condition'] = wizard_field_condition_template['condition']
|
||||||
|
new_template['steps'][2]['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 will not pass"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
expect(response.status).to eq(200)
|
||||||
|
expect(response.parsed_body['final']).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
put '/w/super-mega-fun-wizard/steps/step_2.json', params: {
|
it "excludes the non-included conditional fields from the submissions" do
|
||||||
fields: {
|
new_template = wizard_template.dup
|
||||||
step_2_field_1: "1995-04-23"
|
new_template['steps'][1]['fields'][0]['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 will pass"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
put '/w/super-mega-fun-wizard/steps/step_1.json', params: {
|
put '/w/super-mega-fun-wizard/steps/step_2.json', params: {
|
||||||
fields: {
|
fields: {
|
||||||
step_1_field_1: "Condition will not pass"
|
step_2_field_1: "1995-04-23"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
wizard_id = response.parsed_body['wizard']['id']
|
put '/w/super-mega-fun-wizard/steps/step_1.json', params: {
|
||||||
wizard = CustomWizard::Wizard.create(wizard_id, user)
|
fields: {
|
||||||
submission = wizard.current_submission
|
step_1_field_1: "Condition will not pass"
|
||||||
expect(submission.fields.keys).not_to include("step_2_field_1")
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wizard_id = response.parsed_body['wizard']['id']
|
||||||
|
wizard = CustomWizard::Wizard.create(wizard_id, user)
|
||||||
|
submission = wizard.current_submission
|
||||||
|
expect(submission.fields.keys).not_to include("step_2_field_1")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,29 +2,12 @@
|
||||||
require_relative '../../plugin_helper'
|
require_relative '../../plugin_helper'
|
||||||
|
|
||||||
describe CustomWizard::WizardController do
|
describe CustomWizard::WizardController do
|
||||||
fab!(:user) {
|
fab!(:user) { Fabricate(:user, username: 'angus', email: "angus@email.com", trust_level: TrustLevel[3]) }
|
||||||
Fabricate(
|
let(:wizard_template) { get_wizard_fixture("wizard") }
|
||||||
:user,
|
let(:permitted_json) { get_wizard_fixture("wizard/permitted") }
|
||||||
username: 'angus',
|
|
||||||
email: "angus@email.com",
|
|
||||||
trust_level: TrustLevel[3]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let(:permitted_json) {
|
|
||||||
JSON.parse(
|
|
||||||
File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/permitted.json"
|
|
||||||
).read
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
CustomWizard::Template.save(
|
CustomWizard::Template.save(wizard_template, skip_jobs: true)
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read),
|
|
||||||
skip_jobs: true)
|
|
||||||
@template = CustomWizard::Template.find("super_mega_fun_wizard")
|
@template = CustomWizard::Template.find("super_mega_fun_wizard")
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,13 +4,10 @@ require_relative '../../plugin_helper'
|
||||||
|
|
||||||
describe CustomWizard::BasicWizardSerializer do
|
describe CustomWizard::BasicWizardSerializer do
|
||||||
fab!(:user) { Fabricate(:user) }
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
let(:template) { get_wizard_fixture("wizard") }
|
||||||
|
|
||||||
it 'should return basic wizard attributes' do
|
it 'should return basic wizard attributes' do
|
||||||
CustomWizard::Template.save(
|
CustomWizard::Template.save(template, skip_jobs: true)
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read),
|
|
||||||
skip_jobs: true)
|
|
||||||
json = CustomWizard::BasicWizardSerializer.new(
|
json = CustomWizard::BasicWizardSerializer.new(
|
||||||
CustomWizard::Builder.new("super_mega_fun_wizard", user).build,
|
CustomWizard::Builder.new("super_mega_fun_wizard", user).build,
|
||||||
scope: Guardian.new(user)
|
scope: Guardian.new(user)
|
||||||
|
|
|
@ -4,12 +4,7 @@ require_relative '../../plugin_helper'
|
||||||
|
|
||||||
describe CustomWizard::CustomFieldSerializer do
|
describe CustomWizard::CustomFieldSerializer do
|
||||||
fab!(:user) { Fabricate(:user) }
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") }
|
||||||
let(:custom_field_json) {
|
|
||||||
JSON.parse(File.open(
|
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/custom_field/custom_fields.json"
|
|
||||||
).read)
|
|
||||||
}
|
|
||||||
|
|
||||||
it 'should return custom field attributes' do
|
it 'should return custom field attributes' do
|
||||||
custom_field_json['custom_fields'].each do |field_json|
|
custom_field_json['custom_fields'].each do |field_json|
|
||||||
|
|
17
spec/serializers/custom_wizard/pro/authentication_serializer_spec.rb
Normale Datei
17
spec/serializers/custom_wizard/pro/authentication_serializer_spec.rb
Normale Datei
|
@ -0,0 +1,17 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../../../plugin_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::ProAuthenticationSerializer 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))
|
||||||
|
serialized = described_class.new(auth, root: false).as_json
|
||||||
|
|
||||||
|
expect(serialized[:active]).to eq(true)
|
||||||
|
expect(serialized[:client_id]).to eq(auth.client_id)
|
||||||
|
expect(serialized[:auth_by]).to eq(auth.auth_by)
|
||||||
|
expect(serialized[:auth_at]).to eq(auth.auth_at)
|
||||||
|
end
|
||||||
|
end
|
14
spec/serializers/custom_wizard/pro/subscription_serializer_spec.rb
Normale Datei
14
spec/serializers/custom_wizard/pro/subscription_serializer_spec.rb
Normale Datei
|
@ -0,0 +1,14 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
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))
|
||||||
|
serialized = described_class.new(sub, root: false).as_json
|
||||||
|
|
||||||
|
expect(serialized[:active]).to eq(true)
|
||||||
|
expect(serialized[:type]).to eq('community')
|
||||||
|
expect(serialized[:updated_at]).to eq(sub.updated_at)
|
||||||
|
end
|
||||||
|
end
|
Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen
Laden …
In neuem Issue referenzieren