Remove more subscription related things and integrate with subscription client
Dieser Commit ist enthalten in:
Ursprung
5edfb4c41e
Commit
f607863510
49 geänderte Dateien mit 522 neuen und 1129 gelöschten Zeilen
|
@ -3,8 +3,12 @@ class CustomWizard::AdminController < ::Admin::AdminController
|
|||
before_action :ensure_admin
|
||||
|
||||
def index
|
||||
subcription = CustomWizard::Subscription.new
|
||||
render_json_dump(
|
||||
api_section: ["business"].include?(CustomWizard::Subscription.type)
|
||||
subscribed: subcription.subscribed?,
|
||||
subscription_type: subcription.type,
|
||||
subscription_attributes: CustomWizard::Subscription.attributes,
|
||||
subscription_client_installed: subcription.client_installed?
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
class CustomWizard::AdminCustomFieldsController < CustomWizard::AdminController
|
||||
def index
|
||||
render_json_dump(
|
||||
custom_fields: custom_field_list,
|
||||
subscribed: CustomWizard::Subscription.subscribed?,
|
||||
subscription: CustomWizard::Subscription.type
|
||||
custom_fields: custom_field_list
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -10,9 +10,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
|||
),
|
||||
field_types: CustomWizard::Field.types,
|
||||
realtime_validations: CustomWizard::RealtimeValidation.types,
|
||||
custom_fields: custom_field_list,
|
||||
subscribed: CustomWizard::Subscription.subscribed?,
|
||||
subscription: CustomWizard::Subscription.type
|
||||
custom_fields: custom_field_list
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -3,29 +3,6 @@ import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
|||
import { alias, equal, or } from "@ember/object/computed";
|
||||
import I18n from "I18n";
|
||||
|
||||
import wizardSchema, {
|
||||
requiringAdditionalSubscription,
|
||||
subscriptionLevel,
|
||||
} from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-schema";
|
||||
|
||||
const generateContent = function (kategory, subscription) {
|
||||
let unsubscribedCustomFields = requiringAdditionalSubscription(
|
||||
subscription,
|
||||
"custom_fields",
|
||||
kategory
|
||||
);
|
||||
return wizardSchema.custom_field[kategory].reduce((result, item) => {
|
||||
let disabled = unsubscribedCustomFields.includes(item);
|
||||
result.push({
|
||||
id: item,
|
||||
name: I18n.t(`admin.wizard.custom_field.${kategory}.${item}`),
|
||||
subscription: subscriptionLevel(item, "custom_fields", kategory),
|
||||
disabled,
|
||||
});
|
||||
return result;
|
||||
}, []);
|
||||
};
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "tr",
|
||||
topicSerializers: ["topic_view", "topic_list_item"],
|
||||
|
@ -58,16 +35,6 @@ export default Component.extend({
|
|||
}
|
||||
},
|
||||
|
||||
@discourseComputed("subscription")
|
||||
customFieldTypes(subscription) {
|
||||
return generateContent("type", subscription);
|
||||
},
|
||||
|
||||
@discourseComputed("subscription")
|
||||
customFieldKlasses(subscription) {
|
||||
return generateContent("klass", subscription);
|
||||
},
|
||||
|
||||
@observes("field.klass")
|
||||
clearSerializersWhenClassChanges() {
|
||||
this.set("field.serializers", null);
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
||||
import wizardSchema, {
|
||||
requiringAdditionalSubscription,
|
||||
subscriptionLevel,
|
||||
} from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-schema";
|
||||
import wizardSchema from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-schema";
|
||||
import { subscriptionSelectKitContent } from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-subscription";
|
||||
import { empty, equal, or } from "@ember/object/computed";
|
||||
import { notificationLevels, selectKitContent } from "../lib/wizard";
|
||||
import { computed } from "@ember/object";
|
||||
|
@ -97,22 +95,8 @@ export default Component.extend(UndoChanges, {
|
|||
return apis.find((a) => a.name === api).endpoints;
|
||||
},
|
||||
|
||||
@discourseComputed("subscription")
|
||||
actionTypes(subscription) {
|
||||
let unsubscribedActions = requiringAdditionalSubscription(
|
||||
subscription,
|
||||
"actions",
|
||||
""
|
||||
);
|
||||
return Object.keys(wizardSchema.action.types).reduce((result, type) => {
|
||||
let disabled = unsubscribedActions.includes(type);
|
||||
result.push({
|
||||
id: type,
|
||||
name: I18n.t(`admin.wizard.action.${type}.label`),
|
||||
subscription: subscriptionLevel(type, "actions", ""),
|
||||
disabled,
|
||||
});
|
||||
return result;
|
||||
}, []);
|
||||
@discourseComputed
|
||||
actionTypes() {
|
||||
return subscriptionSelectKitContent("action", "types");
|
||||
},
|
||||
});
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Subscription from "../mixins/subscription";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Component.extend(Subscription, {
|
||||
tagName: 'a',
|
||||
classNameBindings: [":wizard-subscription-badge", "subscriptionType"],
|
||||
attributeBindings: ["title"],
|
||||
|
||||
@discourseComputed("subscriptionType")
|
||||
i18nKey(type) {
|
||||
return `admin.wizard.subscription_container.type.${type ? type : "none"}`;
|
||||
},
|
||||
|
||||
@discourseComputed("i18nKey")
|
||||
title(i18nKey) {
|
||||
return I18n.t(`${i18nKey}.title`);
|
||||
},
|
||||
|
||||
@discourseComputed("i18nKey")
|
||||
label(i18nKey) {
|
||||
return I18n.t(`${i18nKey}.label`);
|
||||
},
|
||||
|
||||
click() {
|
||||
DiscourseURL.routeTo(this.subscriptionLink);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,26 @@
|
|||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Subscription from "../mixins/subscription";
|
||||
|
||||
export default Component.extend(Subscription, {
|
||||
classNameBindings: [":wizard-subscription-container", "subscribed"],
|
||||
|
||||
@discourseComputed("subscribed")
|
||||
subscribedIcon(subscribed) {
|
||||
return subscribed ? "check" : "dash";
|
||||
},
|
||||
|
||||
@discourseComputed("subscribed")
|
||||
subscribedLabel(subscribed) {
|
||||
return `admin.wizard.subscription_container.${
|
||||
subscribed ? "subscribed" : "not_subscribed"
|
||||
}.label`;
|
||||
},
|
||||
|
||||
@discourseComputed("subscribed")
|
||||
subscribedTitle(subscribed) {
|
||||
return `admin.wizard.subscription_container.${
|
||||
subscribed ? "subscribed" : "not_subscribed"
|
||||
}.title`;
|
||||
}
|
||||
});
|
|
@ -1,6 +1,21 @@
|
|||
import SingleSelectComponent from "select-kit/components/single-select";
|
||||
import Subscription from "../mixins/subscription";
|
||||
import wizardSchema from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-schema";
|
||||
import {
|
||||
subscriptionTypeSufficient,
|
||||
subscriptionTypes
|
||||
} from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-subscription";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default SingleSelectComponent.extend({
|
||||
const nameKey = function(feature, attribute, value) {
|
||||
if (feature === 'action') {
|
||||
return `admin.wizard.action.${value}.label`;
|
||||
} else {
|
||||
return `admin.wizard.${feature}.${attribute}.${value}`;
|
||||
}
|
||||
}
|
||||
|
||||
export default SingleSelectComponent.extend(Subscription, {
|
||||
classNames: ["combo-box", "wizard-subscription-selector"],
|
||||
|
||||
selectKitOptions: {
|
||||
|
@ -13,6 +28,38 @@ export default SingleSelectComponent.extend({
|
|||
caretDownIcon: "caret-down",
|
||||
},
|
||||
|
||||
requiredSubscriptionType(feature, attribute, value) {
|
||||
let attributes = this.subscriptionAttributes[feature];
|
||||
if (!attributes || !attributes[attribute]) return null;
|
||||
|
||||
let requiredType = null;
|
||||
Object.keys(attributes[attribute]).some(subscriptionType => {
|
||||
let values = attributes[attribute][subscriptionType];
|
||||
if (values[0] === "*" || values.includes(value)) {
|
||||
if (subscriptionTypes.includes(subscriptionType)) {
|
||||
requiredType = subscriptionType;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
return requiredType;
|
||||
},
|
||||
|
||||
@discourseComputed('feature', 'attribute')
|
||||
content(feature, attribute) {
|
||||
return wizardSchema[feature][attribute].map((value) => {
|
||||
let requiredSubscriptionType = this.requiredSubscriptionType(feature, attribute, value);
|
||||
return {
|
||||
id: value,
|
||||
name: I18n.t(nameKey(feature, attribute, value)),
|
||||
subscriptionType: requiredSubscriptionType,
|
||||
disabled: !subscriptionTypeSufficient(this.subscriptionType, requiredSubscriptionType)
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
modifyComponentForRow() {
|
||||
return "wizard-subscription-selector/wizard-subscription-selector-row";
|
||||
},
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
</label>
|
||||
<div class="controls">
|
||||
{{combo-box
|
||||
value=wizardListVal
|
||||
content=wizardList
|
||||
onChange=(action "changeWizard")
|
||||
options=(hash
|
||||
none="admin.wizard.select"
|
||||
)}}
|
||||
value=wizardListVal
|
||||
content=wizardList
|
||||
onChange=(action "changeWizard")
|
||||
options=(hash
|
||||
none="admin.wizard.select"
|
||||
)}}
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -14,6 +14,7 @@ import I18n from "I18n";
|
|||
export default Controller.extend({
|
||||
hasName: notEmpty("wizard.name"),
|
||||
|
||||
|
||||
@observes("currentStep")
|
||||
resetCurrentObjects() {
|
||||
const currentStep = this.currentStep;
|
||||
|
|
|
@ -1,26 +1,7 @@
|
|||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import { isPresent } from "@ember/utils";
|
||||
import { A } from "@ember/array";
|
||||
import Controller from "@ember/controller";
|
||||
import { equal } from "@ember/object/computed";
|
||||
|
||||
export default Controller.extend({
|
||||
adminWizardsNotices: controller(),
|
||||
|
||||
unsubscribe() {
|
||||
this.messageBus.unsubscribe("/custom-wizard/notices");
|
||||
},
|
||||
|
||||
subscribe() {
|
||||
this.unsubscribe();
|
||||
this.messageBus.subscribe("/custom-wizard/notices", (data) => {
|
||||
if (isPresent(data.active_notice_count)) {
|
||||
this.set("activeNoticeCount", data.active_notice_count);
|
||||
this.adminWizardsNotices.setProperties({
|
||||
notices: A(),
|
||||
page: 0,
|
||||
canLoadMore: true,
|
||||
});
|
||||
this.adminWizardsNotices.loadMoreNotices();
|
||||
}
|
||||
});
|
||||
},
|
||||
businessSubscription: equal('subscriptionType', 'business'),
|
||||
standardSubscription: equal('subscriptionType', 'standard')
|
||||
});
|
||||
|
|
|
@ -58,16 +58,6 @@ export default {
|
|||
path: "/manager",
|
||||
resetNamespace: true,
|
||||
});
|
||||
|
||||
this.route("adminWizardsSubscription", {
|
||||
path: "/subscription",
|
||||
resetNamespace: true,
|
||||
});
|
||||
|
||||
this.route("adminWizardsNotices", {
|
||||
path: "/notices",
|
||||
resetNamespace: true,
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
|
|
|
@ -203,101 +203,17 @@ const custom_field = {
|
|||
type: ["string", "boolean", "integer", "json"],
|
||||
};
|
||||
|
||||
const subscription_levels = {
|
||||
standard: {
|
||||
actions: ["send_message", "add_to_group", "watch_categories"],
|
||||
custom_fields: {
|
||||
klass: [],
|
||||
type: ["json"],
|
||||
},
|
||||
},
|
||||
|
||||
business: {
|
||||
actions: ["create_category", "create_group", "send_to_api"],
|
||||
custom_fields: {
|
||||
klass: ["group", "category"],
|
||||
type: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
field.type = Object.keys(field.types);
|
||||
action.type = Object.keys(action.types);
|
||||
|
||||
const wizardSchema = {
|
||||
wizard,
|
||||
step,
|
||||
field,
|
||||
custom_field,
|
||||
action,
|
||||
subscription_levels,
|
||||
action
|
||||
};
|
||||
|
||||
export function requiringAdditionalSubscription(
|
||||
currentSubscription,
|
||||
category,
|
||||
subCategory
|
||||
) {
|
||||
switch (category) {
|
||||
case "actions":
|
||||
switch (currentSubscription) {
|
||||
case "business":
|
||||
return [];
|
||||
case "standard":
|
||||
return subscription_levels["business"][category];
|
||||
default:
|
||||
return subscription_levels["standard"][category].concat(
|
||||
subscription_levels["business"][category]
|
||||
);
|
||||
}
|
||||
case "custom_fields":
|
||||
switch (currentSubscription) {
|
||||
case "business":
|
||||
return [];
|
||||
case "standard":
|
||||
return subscription_levels["business"][category][subCategory];
|
||||
default:
|
||||
return subscription_levels["standard"][category][subCategory].concat(
|
||||
subscription_levels["business"][category][subCategory]
|
||||
);
|
||||
}
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export function subscriptionLevel(type, category, subCategory) {
|
||||
switch (category) {
|
||||
case "actions":
|
||||
if (subscription_levels["business"].actions.includes(type)) {
|
||||
return "business";
|
||||
} else {
|
||||
if (subscription_levels["standard"].actions.includes(type)) {
|
||||
return "standard";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
case "custom_fields":
|
||||
if (
|
||||
subscription_levels["business"].custom_fields[subCategory].includes(
|
||||
type
|
||||
)
|
||||
) {
|
||||
return "business";
|
||||
} else {
|
||||
if (
|
||||
subscription_levels["standard"].custom_fields[subCategory].includes(
|
||||
type
|
||||
)
|
||||
) {
|
||||
return "standard";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
export function buildFieldTypes(types) {
|
||||
wizardSchema.field.types = types;
|
||||
}
|
||||
|
|
17
assets/javascripts/discourse/lib/wizard-subscription.js.es6
Normale Datei
17
assets/javascripts/discourse/lib/wizard-subscription.js.es6
Normale Datei
|
@ -0,0 +1,17 @@
|
|||
const subscriptionTypes = [
|
||||
'standard',
|
||||
'business'
|
||||
]
|
||||
|
||||
function subscriptionTypeSufficient(subscriptionType, requiredType) {
|
||||
if (requiredType && !subscriptionType) return false;
|
||||
if (requiredType === 'none' || requiredType === null) return true;
|
||||
if (requiredType === 'standard' && subscriptionTypes.includes(subscriptionType)) return true;
|
||||
if (requiredType === 'business' && subscriptionType === 'business') return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
export {
|
||||
subscriptionTypeSufficient,
|
||||
subscriptionTypes
|
||||
}
|
26
assets/javascripts/discourse/mixins/subscription.js.es6
Normale Datei
26
assets/javascripts/discourse/mixins/subscription.js.es6
Normale Datei
|
@ -0,0 +1,26 @@
|
|||
import Mixin from "@ember/object/mixin";
|
||||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
import { readOnly } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Mixin.create({
|
||||
subscriptionLandingUrl: "https://custom-wizard.pavilion.tech",
|
||||
subscriptionClientUrl: "/admin/plugins/subscription-client",
|
||||
|
||||
@discourseComputed
|
||||
adminWizards() {
|
||||
return getOwner(this).lookup('controller:admin-wizards');
|
||||
},
|
||||
|
||||
subscribed: readOnly('adminWizards.subscribed'),
|
||||
subscriptionType: readOnly('adminWizards.subscriptionType'),
|
||||
businessSubscription: readOnly('adminWizards.businessSubscription'),
|
||||
standardSubscription: readOnly('adminWizards.standardSubscription'),
|
||||
subscriptionAttributes: readOnly('adminWizards.subscriptionAttributes'),
|
||||
subscriptionClientInstalled: readOnly('adminWizards.subscriptionClientInstalled'),
|
||||
|
||||
@discourseComputed("subscriptionClientInstalled")
|
||||
subscriptionLink(subscriptionClientInstalled) {
|
||||
return subscriptionClientInstalled ? this.subscriptionClientUrl : this.subscriptionLandingUrl;
|
||||
}
|
||||
});
|
|
@ -9,13 +9,9 @@ export default DiscourseRoute.extend({
|
|||
|
||||
setupController(controller, model) {
|
||||
const customFields = A(model.custom_fields || []);
|
||||
const subscribed = model.subscribed;
|
||||
const subscription = model.subscription;
|
||||
|
||||
controller.setProperties({
|
||||
customFields,
|
||||
subscribed,
|
||||
subscription,
|
||||
customFields
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
@ -38,9 +38,7 @@ export default DiscourseRoute.extend({
|
|||
wizard,
|
||||
currentStep: wizard.steps[0],
|
||||
currentAction: wizard.actions[0],
|
||||
creating: model.create,
|
||||
subscribed: parentModel.subscribed,
|
||||
subscription: parentModel.subscription,
|
||||
creating: model.create
|
||||
};
|
||||
|
||||
controller.setProperties(props);
|
||||
|
|
|
@ -7,21 +7,17 @@ export default DiscourseRoute.extend({
|
|||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
controller.set("api_section", model.api_section);
|
||||
|
||||
if (model.active_notice_count) {
|
||||
controller.set("activeNoticeCount", model.active_notice_count);
|
||||
}
|
||||
if (model.featured_notices) {
|
||||
controller.set("featuredNotices", model.featured_notices);
|
||||
}
|
||||
|
||||
controller.subscribe();
|
||||
controller.setProperties({
|
||||
subscribed: model.subscribed,
|
||||
subscriptionType: model.subscription_type,
|
||||
subscriptionAttributes: model.subscription_attributes,
|
||||
subscriptionClientInstalled: model.subscription_client_installed
|
||||
});
|
||||
},
|
||||
|
||||
afterModel(model, transition) {
|
||||
if (transition.targetName === "adminWizards.index") {
|
||||
this.transitionTo("adminWizardsWizard");
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
|
|
@ -32,9 +32,7 @@
|
|||
{{custom-field-input
|
||||
field=field
|
||||
removeField=(action "removeField")
|
||||
saveField=(action "saveField")
|
||||
subscribed=subscribed
|
||||
subscription=subscription}}
|
||||
saveField=(action "saveField")}}
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{{#subscription-container subscribed=subscribed}}
|
||||
{{#wizard-subscription-container}}
|
||||
<div class="setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.save_submissions"}}</label>
|
||||
|
@ -146,7 +146,7 @@
|
|||
<span>{{i18n "admin.wizard.restart_on_revisit_label"}}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{/subscription-container}}
|
||||
{{/wizard-subscription-container}}
|
||||
</div>
|
||||
|
||||
{{wizard-links
|
||||
|
@ -177,9 +177,7 @@
|
|||
wizard=wizard
|
||||
apis=apis
|
||||
removeAction="removeAction"
|
||||
wizardFields=wizardFields
|
||||
subscribed=subscribed
|
||||
subscription=subscription}}
|
||||
wizardFields=wizardFields}}
|
||||
{{/each}}
|
||||
|
||||
<div class="admin-wizard-buttons">
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
{{nav-item route="adminWizardsWizard" label="admin.wizard.nav_label"}}
|
||||
{{nav-item route="adminWizardsCustomFields" label="admin.wizard.custom_field.nav_label"}}
|
||||
{{nav-item route="adminWizardsSubmissions" label="admin.wizard.submissions.nav_label"}}
|
||||
{{#if api_section}}
|
||||
{{#if businessSubscription}}
|
||||
{{nav-item route="adminWizardsApi" label="admin.wizard.api.nav_label"}}
|
||||
{{/if}}
|
||||
{{nav-item route="adminWizardsLogs" label="admin.wizard.log.nav_label"}}
|
||||
{{nav-item route="adminWizardsManager" label="admin.wizard.manager.nav_label"}}
|
||||
|
||||
<div class="admin-actions">
|
||||
{{wizard-subscription-badge}}
|
||||
<a target="_blank" class="btn btn-pavilion-support" rel="noreferrer noopener" href="https://thepavilion.io/w/support" title={{i18n "admin.wizard.support_button.title"}}>
|
||||
{{d-icon "far-life-ring"}}{{i18n "admin.wizard.support_button.label"}}
|
||||
</a>
|
||||
|
|
|
@ -2,16 +2,22 @@
|
|||
<td>
|
||||
{{wizard-subscription-selector
|
||||
value=field.klass
|
||||
content=customFieldKlasses
|
||||
none="admin.wizard.custom_field.klass.select"
|
||||
onChange=(action (mut field.klass))}}
|
||||
feature="custom_field"
|
||||
attribute="klass"
|
||||
onChange=(action (mut field.klass))
|
||||
options=(hash
|
||||
none="admin.wizard.custom_field.klass.select"
|
||||
)}}
|
||||
</td>
|
||||
<td>
|
||||
{{wizard-subscription-selector
|
||||
value=field.type
|
||||
content=customFieldTypes
|
||||
none="admin.wizard.custom_field.type.select"
|
||||
onChange=(action (mut field.type))}}
|
||||
feature="custom_field"
|
||||
attribute="type"
|
||||
onChange=(action (mut field.type))
|
||||
options=(hash
|
||||
none="admin.wizard.custom_field.type.select"
|
||||
)}}
|
||||
</td>
|
||||
<td class="input">
|
||||
{{input
|
||||
|
@ -22,8 +28,10 @@
|
|||
{{multi-select
|
||||
value=field.serializers
|
||||
content=serializerContent
|
||||
none="admin.wizard.custom_field.serializers.select"
|
||||
onChange=(action (mut field.serializers))}}
|
||||
onChange=(action (mut field.serializers))
|
||||
options=(hash
|
||||
none="admin.wizard.custom_field.serializers.select"
|
||||
)}}
|
||||
</td>
|
||||
<td class="actions">
|
||||
{{#if loading}}
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
<div class="setting-value">
|
||||
{{wizard-subscription-selector
|
||||
value=action.type
|
||||
content=actionTypes
|
||||
feature="action"
|
||||
attribute="type"
|
||||
onChange=(action "changeType")
|
||||
options=(hash
|
||||
none="admin.wizard.select_type"
|
||||
|
|
|
@ -222,7 +222,7 @@
|
|||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#subscription-container subscribed=subscribed}}
|
||||
{{#wizard-subscription-container}}
|
||||
<div class="setting full field-mapper-setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.condition"}}</label>
|
||||
|
@ -237,7 +237,7 @@
|
|||
|
||||
<div class="setting full field-mapper-setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.index"}}</label>>
|
||||
<label>{{i18n "admin.wizard.index"}}</label>
|
||||
</div>
|
||||
|
||||
<div class="setting-value">
|
||||
|
@ -248,10 +248,9 @@
|
|||
</div>
|
||||
|
||||
{{#if isCategory}}
|
||||
<div class="setting pro">
|
||||
<div class="setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.field.property"}}</label>
|
||||
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||
</div>
|
||||
|
||||
<div class="setting-value">
|
||||
|
@ -269,4 +268,4 @@
|
|||
{{#if validations}}
|
||||
{{wizard-realtime-validations field=field validations=validations}}
|
||||
{{/if}}
|
||||
{{/subscription-container}}
|
||||
{{/wizard-subscription-container}}
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{{#subscription-container subscribed=subscribed}}
|
||||
{{#wizard-subscription-container}}
|
||||
<div class="setting full field-mapper-setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.condition"}}</label>
|
||||
|
@ -56,11 +56,11 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting full field-mapper-setting pro">
|
||||
<div class="setting full field-mapper-setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.step.required_data.label"}}</label>
|
||||
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
||||
</div>
|
||||
|
||||
<div class="setting-value">
|
||||
{{wizard-mapper
|
||||
inputs=step.required_data
|
||||
|
@ -99,7 +99,7 @@
|
|||
)}}
|
||||
</div>
|
||||
</div>
|
||||
{{/subscription-container}}
|
||||
{{/wizard-subscription-container}}
|
||||
|
||||
{{wizard-links
|
||||
itemType="field"
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<svg width="300px" height="300px" viewBox="0 0 300 300" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="pavilion-logo" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path id="Combined-Shape" stroke="currentColor" stroke-width="35" d="M41.1381822,291.00006 L40.5778853,130.009744 M258.850727,291.638415 L259.290397,130.37133 M36.0002279,140.721678 L139.995368,36.2122772 M263.350577,141.009083 L138.927245,16.2478517"></path>
|
||||
</g>
|
||||
</svg>
|
||||
<span>{{label}}</span>
|
Nachher Breite: | Höhe: | Größe: 538 B |
|
@ -1,7 +1,7 @@
|
|||
<div class="subscription-header">
|
||||
<h3>{{i18n "admin.wizard.subscription_container.title"}}</h3>
|
||||
<h4>{{i18n "admin.wizard.subscription_container.title"}}</h4>
|
||||
|
||||
<a href="/admin/wizards/subscription" title={{i18n subscribedTitle}}>
|
||||
<a href={{subscriptionLink}} title={{i18n subscribedTitle}}>
|
||||
{{d-icon subscribedIcon}}
|
||||
{{i18n subscribedLabel}}
|
||||
</a>
|
|
@ -7,8 +7,10 @@
|
|||
shouldDisplayClearableButton=shouldDisplayClearableButton
|
||||
}}
|
||||
|
||||
{{#if selectedContent.subscription}}
|
||||
<span class="subscription-label">{{i18n "admin.wizard.subscription.label"}}</span>
|
||||
{{#if selectedContent.subscriptionType}}
|
||||
<span class="subscription-label">
|
||||
{{selectedContent.subscriptionType}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{d-icon caretIcon class="caret-icon"}}
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
|
||||
<div class="texts">
|
||||
<span class="name">{{html-safe label}}</span>
|
||||
{{#if item.subscription}}
|
||||
{{#if item.subscriptionType}}
|
||||
<span class="subscription-label">
|
||||
{{item.subscription}}
|
||||
{{item.subscriptionType}}
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -25,6 +25,14 @@ $error: #ef1700;
|
|||
}
|
||||
}
|
||||
|
||||
.admin-wizards .admin-actions {
|
||||
display: flex;
|
||||
|
||||
.btn-pavilion-support {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.wizard-message {
|
||||
background-color: var(--primary-low);
|
||||
width: 100%;
|
||||
|
@ -156,6 +164,16 @@ $error: #ef1700;
|
|||
@extend .wizard-settings-group;
|
||||
}
|
||||
|
||||
.admin-wizard-container.settings {
|
||||
.wizard-settings {
|
||||
.wizard-subscription-container {
|
||||
[class~="setting"] {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wizard-custom-field {
|
||||
background: transparent;
|
||||
background-color: var(--primary-very-low);
|
||||
|
@ -802,84 +820,6 @@ $error: #ef1700;
|
|||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.admin-wizards-subscription {
|
||||
.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-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-subscription-selector.select-kit.single-select {
|
||||
.select-kit-row {
|
||||
.texts {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
&.disabled {
|
||||
background: var(--primary-low);
|
||||
}
|
||||
}
|
||||
|
||||
.subscription-label {
|
||||
margin-left: 0.75em;
|
||||
padding-top: 0.25em;
|
||||
color: var(--tertiary);
|
||||
font-size: 0.75em;
|
||||
}
|
||||
}
|
||||
|
||||
.btn.btn-pavilion-support {
|
||||
background: var(--pavilion-primary);
|
||||
color: var(--pavilion-secondary);
|
||||
|
@ -899,7 +839,7 @@ $error: #ef1700;
|
|||
}
|
||||
}
|
||||
|
||||
.subscription-container {
|
||||
.wizard-subscription-container {
|
||||
width: 100%;
|
||||
padding: 1em;
|
||||
background-color: rgba($pavilion_primary, 0.1);
|
||||
|
@ -907,158 +847,79 @@ $error: #ef1700;
|
|||
.subscription-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1em;
|
||||
margin-bottom: .25em;
|
||||
|
||||
h3 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--pavilion-primary);
|
||||
color: var(--primary);
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.subscribed) .subscription-settings {
|
||||
filter: blur(1px);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.admin-wizards-notices {
|
||||
.wizard-table {
|
||||
overflow: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.wizard-notice {
|
||||
padding: 0.75em;
|
||||
margin-bottom: 1em;
|
||||
border: 1px solid var(--primary-low);
|
||||
|
||||
&.dismissed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.expired .notice-badge:not(.notice-expired-at),
|
||||
&.expired a,
|
||||
&.expired p {
|
||||
color: var(--primary-medium) !important;
|
||||
}
|
||||
|
||||
.notice-badge {
|
||||
padding: 0 0.5em;
|
||||
}
|
||||
|
||||
.notice-header {
|
||||
display: flex;
|
||||
|
||||
.notice-title {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.notice-header-right {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.notice-badge {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dismiss-notice-container,
|
||||
.hide-notice-container {
|
||||
width: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dismiss-notice,
|
||||
.hide-notice {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.d-icon {
|
||||
margin-right: 0;
|
||||
color: var(--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notice-badge {
|
||||
.wizard-subscription-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 25px;
|
||||
max-height: 34px;
|
||||
box-sizing: border-box;
|
||||
color: var(--primary) !important;
|
||||
}
|
||||
|
||||
.admin-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.wizard-notices-link {
|
||||
position: relative;
|
||||
margin-right: 10px;
|
||||
cursor: pointer;
|
||||
padding: .5em .65em;
|
||||
background-color: rgba($primary-medium, 0.05);
|
||||
border: 1.5px solid rgba($primary-medium, 0.5);
|
||||
color: $primary-medium;
|
||||
|
||||
div > a {
|
||||
@include btn;
|
||||
color: var(--secondary) !important;
|
||||
background-color: var(--primary-medium);
|
||||
&:hover {
|
||||
color: $primary-medium;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: var(--tertiary) !important;
|
||||
color: var(--secondary) !important;
|
||||
svg {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
margin-right: 0.45em;
|
||||
margin-bottom: 0.15em;
|
||||
}
|
||||
|
||||
&.standard {
|
||||
background-color: rgba($subscription_standard, 0.05);
|
||||
border: 1.5px solid rgba($subscription_standard, 0.5);
|
||||
color: $subscription_standard;
|
||||
}
|
||||
|
||||
&.business {
|
||||
background-color: $subscription_business;
|
||||
border: 1.5px solid $subscription_business;
|
||||
color: $secondary;
|
||||
}
|
||||
|
||||
.d-icon {
|
||||
margin-right: 0.75em;
|
||||
}
|
||||
}
|
||||
|
||||
.wizard-subscription-selector.select-kit.single-select {
|
||||
.select-kit-row {
|
||||
.texts {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
&.disabled {
|
||||
background: var(--primary-low);
|
||||
cursor: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.active-notice-count {
|
||||
background-color: $danger;
|
||||
color: $secondary;
|
||||
border-radius: 50%;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
right: -8px;
|
||||
font-size: 0.7em;
|
||||
}
|
||||
|
||||
a.show-notice-message {
|
||||
padding: 0.25em 0.5em;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.wizard-notice,
|
||||
.wizard-notice-row:not(.expired):not(.dismissed) {
|
||||
&.info {
|
||||
background-color: rgba($info, 0.1);
|
||||
border: 1px solid rgba($info, 0.5);
|
||||
}
|
||||
&.warning,
|
||||
&.connection-error {
|
||||
background-color: rgba($warning, 0.1);
|
||||
border: 1px solid rgba($warning, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.notice-message {
|
||||
position: relative;
|
||||
|
||||
.cooked-notice-message {
|
||||
background-color: var(--secondary);
|
||||
padding: 1em;
|
||||
z-index: 1;
|
||||
box-shadow: shadow("dropdown");
|
||||
border-top: 1px solid var(--primary-low);
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
.subscription-label {
|
||||
margin-left: 0.75em;
|
||||
padding-top: 0.25em;
|
||||
color: var(--pavilion-primary);
|
||||
font-size: 0.75em;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,13 @@ $pavilion_primary: #3c1c8c;
|
|||
$pavilion_secondary: #ffffff;
|
||||
$pavilion_warning: rgb(243, 163, 61);
|
||||
|
||||
$subscription_standard: $pavilion_primary;
|
||||
$subscription_business: #333;
|
||||
|
||||
:root {
|
||||
--pavilion-primary: #{$pavilion_primary};
|
||||
--pavilion-secondary: #{$pavilion_secondary};
|
||||
--pavilion-warning: #{$pavilion_warning};
|
||||
--subscription-standard: #{$subscription_standard};
|
||||
--subscription-business: #{$subscription_business};
|
||||
}
|
||||
|
|
|
@ -474,53 +474,16 @@ en:
|
|||
not_subscribed:
|
||||
label: Not Subscribed
|
||||
title: Subscribe to use these features
|
||||
|
||||
subscription:
|
||||
nav_label: Subscription
|
||||
label: In subscription
|
||||
additional_label: "Add subscription"
|
||||
title: Custom Wizard Subscription
|
||||
authorize: Authorize
|
||||
authorized: Authorized
|
||||
unauthorize: cancel
|
||||
not_subscribed: You're not currently subscribed
|
||||
subscription:
|
||||
title:
|
||||
standard: Standard Subscription
|
||||
business: Business Subscription
|
||||
status:
|
||||
active: Active
|
||||
inactive: Inactive
|
||||
update: Update
|
||||
last_updated: Last updated
|
||||
|
||||
notice:
|
||||
plugin: Custom Wizard Plugin
|
||||
message: Message
|
||||
time: Time
|
||||
status: Status
|
||||
title: Title
|
||||
dismiss:
|
||||
label: Dismiss
|
||||
title: Dismiss notice
|
||||
dismiss_all:
|
||||
label: Dismiss All
|
||||
title: Dismiss all informational Custom Wizard notices
|
||||
confirm: Are you sure you want to dismiss all informational Custom Wizard notices?
|
||||
active: active
|
||||
created_at: issued
|
||||
updated_at: updated
|
||||
expired_at: expired
|
||||
dismissed_at: dismissed
|
||||
type:
|
||||
label: Type
|
||||
info: Information
|
||||
warning: Warning
|
||||
connection_error: Connection Error
|
||||
|
||||
notices:
|
||||
nav_label: Notices
|
||||
title: Plugin Notices
|
||||
none:
|
||||
label: Not Subscribed
|
||||
title: There is no Custom Wizard subscription active on this forum.
|
||||
business:
|
||||
label: Business
|
||||
title: There is a Custom Wizard Business subscription active on this forum.
|
||||
standard:
|
||||
label: Standard
|
||||
title: There is a Custom Wizard Standard subscription active on this forum.
|
||||
|
||||
wizard_js:
|
||||
group:
|
||||
|
|
|
@ -84,7 +84,7 @@ class ::CustomWizard::CustomField
|
|||
next
|
||||
end
|
||||
|
||||
if attr == 'klass' && @subscription.requires_additional_subscription("custom_fields", "klass").include?(value)
|
||||
if attr == 'klass' && @subscription.includes?(:custom_field, :klass, value)
|
||||
add_error(I18n.t("wizard.custom_field.error.subscription_type", type: value))
|
||||
end
|
||||
|
||||
|
@ -99,7 +99,7 @@ class ::CustomWizard::CustomField
|
|||
add_error(I18n.t("#{i18n_key}.unsupported_type", type: value))
|
||||
end
|
||||
|
||||
if attr == 'type' && @subscription.requires_additional_subscription("custom_fields", "type").include?(value)
|
||||
if attr == 'type' && @subscription.includes?(:custom_field, :type, value)
|
||||
add_error(I18n.t("wizard.custom_field.error.subscription_type", type: value))
|
||||
end
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@ class CustomWizard::Mapper
|
|||
@data = params[:data] || {}
|
||||
@user = params[:user]
|
||||
@opts = params[:opts] || {}
|
||||
@subscription = CustomWizard::Subscription.new
|
||||
end
|
||||
|
||||
def perform
|
||||
|
@ -252,7 +251,7 @@ class CustomWizard::Mapper
|
|||
end
|
||||
end
|
||||
|
||||
if opts[:template] && @subscription.subscribed?
|
||||
if opts[:template] && CustomWizard::Subscription.subscribed?
|
||||
template = Liquid::Template.parse(string)
|
||||
string = template.render(data)
|
||||
end
|
||||
|
|
|
@ -1,8 +1,170 @@
|
|||
class CustomWizard::Subscription
|
||||
STANDARD_PRODUCT_ID = 'prod_LNAGVAaIqDsHmB'
|
||||
BUSINESS_PRODUCT_ID = 'prod_LNABQ50maBQ1pY'
|
||||
|
||||
def self.attributes
|
||||
{
|
||||
wizard: {
|
||||
required: {
|
||||
none: [],
|
||||
standard: ['*'],
|
||||
business: ['*']
|
||||
},
|
||||
permitted: {
|
||||
none: [],
|
||||
standard: ['*'],
|
||||
business: ['*']
|
||||
}
|
||||
},
|
||||
step: {
|
||||
condition: {
|
||||
none: [],
|
||||
standard: ['*'],
|
||||
business: ['*']
|
||||
},
|
||||
index: {
|
||||
none: [],
|
||||
standard: ['*'],
|
||||
business: ['*']
|
||||
},
|
||||
required_data: {
|
||||
none: [],
|
||||
standard: ['*'],
|
||||
business: ['*']
|
||||
},
|
||||
permitted_params: {
|
||||
none: [],
|
||||
standard: ['*'],
|
||||
business: ['*']
|
||||
}
|
||||
},
|
||||
field: {
|
||||
condition: {
|
||||
none: [],
|
||||
standard: ['*'],
|
||||
business: ['*']
|
||||
},
|
||||
index: {
|
||||
none: [],
|
||||
standard: ['*'],
|
||||
business: ['*']
|
||||
},
|
||||
type: {
|
||||
none: ['label', 'description', 'image', 'required', 'placeholder', 'file'],
|
||||
standard: ['*'],
|
||||
business: ['*']
|
||||
},
|
||||
prefill: {
|
||||
standard: ['*'],
|
||||
business: ['*']
|
||||
},
|
||||
content: {
|
||||
none: [],
|
||||
standard: ['*'],
|
||||
business: ['*']
|
||||
},
|
||||
realtime_validations: {
|
||||
none: [],
|
||||
standard: ['*'],
|
||||
business: ['*']
|
||||
}
|
||||
},
|
||||
action: {
|
||||
type: {
|
||||
none: [],
|
||||
standard: ['send_message', 'watch_categories', 'add_to_group'],
|
||||
business: ['*']
|
||||
}
|
||||
},
|
||||
custom_field: {
|
||||
klass: {
|
||||
none: ['topic', 'post'],
|
||||
standard: ['topic', 'post'],
|
||||
business: ['*']
|
||||
},
|
||||
type: {
|
||||
none: ['string', 'boolean', 'integer'],
|
||||
standard: ['string', 'boolean', 'integer'],
|
||||
business: ['*']
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def initialize
|
||||
@subscription = find_subscription
|
||||
end
|
||||
|
||||
def includes?(feature, attribute, value)
|
||||
attributes = self.class.attributes[feature]
|
||||
|
||||
## Attribute is not part of a subscription
|
||||
return true unless attributes.present? && attributes.key?(attribute)
|
||||
|
||||
values = attributes[attribute][type]
|
||||
|
||||
## Subscription type does not support the attribute.
|
||||
return false if values.blank?
|
||||
|
||||
## Subscription type supports all values of the attribute.
|
||||
return true if values === "*"
|
||||
|
||||
## Subscription type supports some values of the attributes.
|
||||
values.include?(value)
|
||||
end
|
||||
|
||||
def type
|
||||
return :none unless subscribed?
|
||||
return :standard if standard?
|
||||
return :business if business?
|
||||
end
|
||||
|
||||
def subscribed?
|
||||
standard? || business?
|
||||
end
|
||||
|
||||
def standard?
|
||||
@subscription.product_id === STANDARD_PRODUCT_ID
|
||||
end
|
||||
|
||||
def business?
|
||||
@subscription.product_id === BUSINESS_PRODUCT_ID
|
||||
end
|
||||
|
||||
def client_installed?
|
||||
defined?(SubscriptionClient) == 'constant' && SubscriptionClient.class == Module
|
||||
end
|
||||
|
||||
def find_subscription
|
||||
subscription = nil
|
||||
|
||||
if client_installed?
|
||||
subscription = SubscriptionClientSubscription.active
|
||||
.where(product_id: [STANDARD_PRODUCT_ID, BUSINESS_PRODUCT_ID])
|
||||
.order("product_id = '#{BUSINESS_PRODUCT_ID}' DESC")
|
||||
.first
|
||||
end
|
||||
|
||||
unless subscription
|
||||
subscription = OpenStruct.new(product_id: nil)
|
||||
end
|
||||
|
||||
subscription
|
||||
end
|
||||
|
||||
def self.subscribed?
|
||||
new.subscribed?
|
||||
end
|
||||
|
||||
def self.business?
|
||||
new.business?
|
||||
end
|
||||
|
||||
def self.standard?
|
||||
new.standard?
|
||||
end
|
||||
|
||||
def self.type
|
||||
|
||||
new.type
|
||||
end
|
||||
end
|
||||
|
|
|
@ -56,29 +56,10 @@ class CustomWizard::TemplateValidator
|
|||
|
||||
def self.subscription
|
||||
{
|
||||
wizard: {
|
||||
save_submissions: 'false',
|
||||
restart_on_revisit: 'true',
|
||||
},
|
||||
step: {
|
||||
condition: 'present',
|
||||
index: 'conditional',
|
||||
required_data: 'present',
|
||||
permitted_params: 'present'
|
||||
},
|
||||
field: {
|
||||
condition: 'present',
|
||||
index: 'conditional'
|
||||
},
|
||||
action: {
|
||||
type: %w[
|
||||
send_message
|
||||
add_to_group
|
||||
create_category
|
||||
create_group
|
||||
send_to_api
|
||||
]
|
||||
}
|
||||
wizard: ['save_submissions', 'restart_on_revisit'],
|
||||
step: ['condition', 'index', 'required_data', 'permitted_params'],
|
||||
field: ['condition', 'index'],
|
||||
action: ['type']
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -93,16 +74,8 @@ class CustomWizard::TemplateValidator
|
|||
end
|
||||
|
||||
def validate_subscription(object, type)
|
||||
self.class.subscription[type].each do |property, subscription_type|
|
||||
val = object[property.to_s]
|
||||
is_subscription = (val != nil) && (
|
||||
subscription_type === 'present' && val.present? ||
|
||||
(['true', 'false'].include?(subscription_type) && cast_bool(val) == cast_bool(subscription_type)) ||
|
||||
(subscription_type === 'conditional' && val.is_a?(Hash)) ||
|
||||
(subscription_type.is_a?(Array) && subscription_type.include?(val))
|
||||
)
|
||||
|
||||
if is_subscription && !@subscription.subscribed?
|
||||
self.class.subscription[type].each do |property|
|
||||
if !@subscription.includes?(type, property, object[property])
|
||||
errors.add :base, I18n.t("wizard.validation.subscription", type: type.to_s, property: property)
|
||||
end
|
||||
end
|
||||
|
@ -148,10 +121,6 @@ class CustomWizard::TemplateValidator
|
|||
end
|
||||
end
|
||||
|
||||
def cast_bool(val)
|
||||
ActiveRecord::Type::Boolean.new.cast(val)
|
||||
end
|
||||
|
||||
def validate_liquid_template(object, type)
|
||||
%w[
|
||||
description
|
||||
|
|
25
plugin.rb
25
plugin.rb
|
@ -5,17 +5,13 @@
|
|||
# authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George
|
||||
# contact_emails: support@thepavilion.io
|
||||
# url: https://github.com/paviliondev/discourse-custom-wizard
|
||||
# subscription_url: https://coop.pavilion.tech
|
||||
|
||||
gem 'liquid', '5.0.1', require: true
|
||||
register_asset 'stylesheets/admin/admin.scss', :desktop
|
||||
|
||||
enabled_site_setting :custom_wizard_enabled
|
||||
|
||||
config = Rails.application.config
|
||||
plugin_asset_path = "#{Rails.root}/plugins/discourse-custom-wizard/assets"
|
||||
config.assets.paths << "#{plugin_asset_path}/javascripts"
|
||||
config.assets.paths << "#{plugin_asset_path}/stylesheets/wizard"
|
||||
|
||||
if Rails.env.production?
|
||||
config.assets.precompile += %w{
|
||||
wizard-custom-guest.js
|
||||
|
@ -59,6 +55,24 @@ class ::Sprockets::DirectiveProcessor
|
|||
end
|
||||
end
|
||||
|
||||
## Override necessary due to 'assets/javascripts/wizard', particularly its tests.
|
||||
def each_globbed_asset
|
||||
if @path
|
||||
root_path = "#{File.dirname(@path)}/assets/javascripts/discourse"
|
||||
|
||||
Dir.glob(["#{root_path}/**/*"]).sort.each do |f|
|
||||
f_str = f.to_s
|
||||
if File.directory?(f)
|
||||
yield [f, true]
|
||||
elsif f_str.end_with?(".js.es6") || f_str.end_with?(".hbs") || f_str.end_with?(".hbr")
|
||||
yield [f, false]
|
||||
elsif transpile_js && f_str.end_with?(".js")
|
||||
yield [f, false]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
after_initialize do
|
||||
%w[
|
||||
../lib/custom_wizard/engine.rb
|
||||
|
@ -91,6 +105,7 @@ after_initialize do
|
|||
../lib/custom_wizard/step_updater.rb
|
||||
../lib/custom_wizard/step.rb
|
||||
../lib/custom_wizard/submission.rb
|
||||
../lib/custom_wizard/subscription.rb
|
||||
../lib/custom_wizard/template.rb
|
||||
../lib/custom_wizard/wizard.rb
|
||||
../lib/custom_wizard/api/api.rb
|
||||
|
|
|
@ -1,159 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../plugin_helper'
|
||||
|
||||
describe CustomWizard::Notice do
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
let(:subscription_message) {
|
||||
{
|
||||
title: "Title of message about subscription",
|
||||
message: "Message about subscription",
|
||||
type: "info",
|
||||
created_at: Time.now - 3.day,
|
||||
expired_at: nil
|
||||
}
|
||||
}
|
||||
let(:plugin_status) {
|
||||
{
|
||||
name: 'discourse-custom-wizard',
|
||||
status: 'incompatible',
|
||||
status_changed_at: Time.now - 3.day
|
||||
}
|
||||
}
|
||||
|
||||
context "subscription message" do
|
||||
before do
|
||||
freeze_time
|
||||
stub_request(:get, described_class.subscription_message_url).to_return(status: 200, body: { messages: [subscription_message] }.to_json)
|
||||
described_class.update(skip_plugin: true)
|
||||
end
|
||||
|
||||
it "converts subscription messages into notices" do
|
||||
notice = described_class.list.first
|
||||
expect(notice.type).to eq(described_class.types[:info])
|
||||
expect(notice.message).to eq(subscription_message[:message])
|
||||
expect(notice.created_at.to_datetime).to be_within(1.second).of (subscription_message[:created_at].to_datetime)
|
||||
end
|
||||
|
||||
it "expires notice if subscription message is expired" do
|
||||
subscription_message[:expired_at] = Time.now
|
||||
stub_request(:get, described_class.subscription_message_url).to_return(status: 200, body: { messages: [subscription_message] }.to_json)
|
||||
described_class.update(skip_plugin: true)
|
||||
|
||||
notice = described_class.list(include_all: true).first
|
||||
expect(notice.expired?).to eq(true)
|
||||
end
|
||||
|
||||
it "dismisses informational subscription notices" do
|
||||
notice = described_class.list(include_all: true).first
|
||||
expect(notice.dismissed?).to eq(false)
|
||||
|
||||
notice.dismiss!
|
||||
expect(notice.dismissed?).to eq(true)
|
||||
end
|
||||
|
||||
it "dismisses all informational subscription notices" do
|
||||
4.times do |index|
|
||||
subscription_message[:title] += " #{index}"
|
||||
stub_request(:get, described_class.subscription_message_url).to_return(status: 200, body: { messages: [subscription_message] }.to_json)
|
||||
described_class.update(skip_plugin: true)
|
||||
end
|
||||
expect(described_class.list.count).to eq(5)
|
||||
described_class.dismiss_all
|
||||
expect(described_class.list.count).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
context "plugin status" do
|
||||
before do
|
||||
freeze_time
|
||||
stub_request(:get, described_class.plugin_status_url).to_return(status: 200, body: plugin_status.to_json)
|
||||
described_class.update(skip_subscription: true)
|
||||
end
|
||||
|
||||
it "converts warning into notice" do
|
||||
notice = described_class.list.first
|
||||
expect(notice.type).to eq(described_class.types[:warning])
|
||||
expect(notice.message).to eq(I18n.t("wizard.notice.compatibility_issue.message", domain: described_class.plugin_status_domain))
|
||||
expect(notice.created_at.to_datetime).to be_within(1.second).of (plugin_status[:status_changed_at].to_datetime)
|
||||
end
|
||||
|
||||
it "expires warning notices if status is recommended or compatible" do
|
||||
plugin_status[:status] = 'compatible'
|
||||
plugin_status[:status_changed_at] = Time.now
|
||||
stub_request(:get, described_class.plugin_status_url).to_return(status: 200, body: plugin_status.to_json)
|
||||
described_class.update(skip_subscription: true)
|
||||
|
||||
notice = described_class.list(type: described_class.types[:warning], include_all: true).first
|
||||
expect(notice.expired?).to eq(true)
|
||||
end
|
||||
|
||||
it "hides plugin status warnings" do
|
||||
notice = described_class.list.first
|
||||
expect(notice.hidden?).to eq(false)
|
||||
|
||||
notice.hide!
|
||||
expect(notice.hidden?).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
it "lists notices not expired more than a day ago" do
|
||||
subscription_message[:expired_at] = Time.now - 8.hours
|
||||
stub_request(:get, described_class.subscription_message_url).to_return(status: 200, body: { messages: [subscription_message] }.to_json)
|
||||
stub_request(:get, described_class.plugin_status_url).to_return(status: 200, body: plugin_status.to_json)
|
||||
|
||||
described_class.update
|
||||
expect(described_class.list(include_all: true).length).to eq(2)
|
||||
end
|
||||
|
||||
context "connection errors" do
|
||||
before do
|
||||
freeze_time
|
||||
end
|
||||
|
||||
it "creates an error if connection to notice server fails" do
|
||||
stub_request(:get, described_class.plugin_status_url).to_return(status: 400, body: plugin_status.to_json)
|
||||
described_class.update(skip_subscription: true)
|
||||
|
||||
error = CustomWizard::Notice::ConnectionError.new(:plugin_status)
|
||||
expect(error.current_error.present?).to eq(true)
|
||||
end
|
||||
|
||||
it "only creates one connection error per type at a time" do
|
||||
stub_request(:get, described_class.subscription_message_url).to_return(status: 400, body: { messages: [subscription_message] }.to_json)
|
||||
stub_request(:get, described_class.plugin_status_url).to_return(status: 400, body: plugin_status.to_json)
|
||||
|
||||
5.times { described_class.update }
|
||||
|
||||
plugin_status_errors = CustomWizard::Notice::ConnectionError.new(:plugin_status)
|
||||
subscription_message_errors = CustomWizard::Notice::ConnectionError.new(:subscription_message)
|
||||
|
||||
expect(plugin_status_errors.current_error[:count]).to eq(5)
|
||||
expect(subscription_message_errors.current_error[:count]).to eq(5)
|
||||
end
|
||||
|
||||
it "creates a connection error notice if connection errors reach limit" do
|
||||
stub_request(:get, described_class.plugin_status_url).to_return(status: 400, body: plugin_status.to_json)
|
||||
|
||||
error = CustomWizard::Notice::ConnectionError.new(:plugin_status)
|
||||
error.limit.times { described_class.update(skip_subscription: true) }
|
||||
notice = described_class.list(type: described_class.types[:connection_error]).first
|
||||
|
||||
expect(error.current_error[:count]).to eq(error.limit)
|
||||
expect(notice.type).to eq(described_class.types[:connection_error])
|
||||
end
|
||||
|
||||
it "expires a connection error notice if connection succeeds" do
|
||||
stub_request(:get, described_class.plugin_status_url).to_return(status: 400, body: plugin_status.to_json)
|
||||
error = CustomWizard::Notice::ConnectionError.new(:plugin_status)
|
||||
error.limit.times { described_class.update(skip_subscription: true) }
|
||||
|
||||
stub_request(:get, described_class.plugin_status_url).to_return(status: 200, body: plugin_status.to_json)
|
||||
described_class.update(skip_subscription: true)
|
||||
notice = described_class.list(type: described_class.types[:connection_error], include_all: true).first
|
||||
|
||||
expect(notice.type).to eq(described_class.types[:connection_error])
|
||||
expect(notice.expired_at.present?).to eq(true)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,125 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../plugin_helper'
|
||||
|
||||
describe CustomWizard::Subscription do
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
|
||||
it "initializes subscription authentication and subscription" do
|
||||
subscription = described_class.new
|
||||
expect(subscription.authentication.class).to eq(CustomWizard::Subscription::Authentication)
|
||||
expect(subscription.subscription.class).to eq(CustomWizard::Subscription::Subscription)
|
||||
end
|
||||
|
||||
it "returns authorized and subscribed states" do
|
||||
subscription = described_class.new
|
||||
expect(subscription.authorized?).to eq(false)
|
||||
expect(subscription.subscribed?).to eq(false)
|
||||
end
|
||||
|
||||
context "subscription" do
|
||||
before do
|
||||
@subscription = described_class.new
|
||||
end
|
||||
|
||||
it "updates valid subscriptions" do
|
||||
stub_subscription_request(200, valid_subscription)
|
||||
expect(@subscription.update).to eq(true)
|
||||
expect(@subscription.subscribed?).to eq(true)
|
||||
end
|
||||
|
||||
it "handles invalid subscriptions" do
|
||||
stub_subscription_request(200, invalid_subscription)
|
||||
expect(@subscription.update).to eq(false)
|
||||
expect(@subscription.subscribed?).to eq(false)
|
||||
end
|
||||
|
||||
it "handles subscription http errors" do
|
||||
stub_subscription_request(404, {})
|
||||
expect(@subscription.update).to eq(false)
|
||||
expect(@subscription.subscribed?).to eq(false)
|
||||
end
|
||||
|
||||
it "destroys subscriptions" do
|
||||
stub_subscription_request(200, valid_subscription)
|
||||
expect(@subscription.update).to eq(true)
|
||||
expect(@subscription.destroy_subscription).to eq(true)
|
||||
expect(@subscription.subscribed?).to eq(false)
|
||||
end
|
||||
|
||||
it "has class aliases" do
|
||||
authenticate_subscription
|
||||
stub_subscription_request(200, valid_subscription)
|
||||
expect(described_class.update).to eq(true)
|
||||
expect(described_class.subscribed?).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
context "authentication" do
|
||||
before do
|
||||
@subscription = described_class.new
|
||||
user.update!(admin: true)
|
||||
end
|
||||
|
||||
it "generates a valid authentication request url" do
|
||||
request_id = SecureRandom.hex(32)
|
||||
uri = URI(@subscription.authentication_url(user.id, request_id))
|
||||
expect(uri.host).to eq(@subscription.server)
|
||||
|
||||
parsed_query = Rack::Utils.parse_query uri.query
|
||||
expect(parsed_query['public_key'].present?).to eq(true)
|
||||
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(@subscription.scope)
|
||||
end
|
||||
|
||||
def generate_payload(request_id, user_id)
|
||||
uri = URI(@subscription.authentication_url(user_id, request_id))
|
||||
keys = @subscription.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(@subscription.authentication_response(request_id, payload)).to eq(true)
|
||||
expect(@subscription.authorized?).to eq(true)
|
||||
end
|
||||
|
||||
it "discards authentication response if user who made request as not an admin" do
|
||||
user.update!(admin: false)
|
||||
|
||||
request_id = SecureRandom.hex(32)
|
||||
payload = generate_payload(request_id, user.id)
|
||||
|
||||
expect(@subscription.authentication_response(request_id, payload)).to eq(false)
|
||||
expect(@subscription.authorized?).to eq(false)
|
||||
end
|
||||
|
||||
it "discards authentication response if request_id is invalid" do
|
||||
payload = generate_payload(SecureRandom.hex(32), user.id)
|
||||
|
||||
expect(@subscription.authentication_response(SecureRandom.hex(32), payload)).to eq(false)
|
||||
expect(@subscription.authorized?).to eq(false)
|
||||
end
|
||||
|
||||
it "destroys authentication" do
|
||||
request_id = SecureRandom.hex(32)
|
||||
payload = generate_payload(request_id, user.id)
|
||||
@subscription.authentication_response(request_id, payload)
|
||||
|
||||
expect(@subscription.destroy_authentication).to eq(true)
|
||||
expect(@subscription.authorized?).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,29 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../plugin_helper'
|
||||
|
||||
describe Jobs::CustomWizardUpdateNotices do
|
||||
let(:subscription_message) {
|
||||
{
|
||||
message: "Message about subscription",
|
||||
type: "info",
|
||||
created_at: Time.now - 3.day,
|
||||
expired_at: nil
|
||||
}
|
||||
}
|
||||
let(:plugin_status) {
|
||||
{
|
||||
name: 'discourse-custom-wizard',
|
||||
status: 'incompatible',
|
||||
status_changed_at: Time.now - 3.day
|
||||
}
|
||||
}
|
||||
|
||||
it "updates the notices" do
|
||||
stub_request(:get, CustomWizard::Notice.subscription_message_url).to_return(status: 200, body: { messages: [subscription_message] }.to_json)
|
||||
stub_request(:get, CustomWizard::Notice.plugin_status_url).to_return(status: 200, body: plugin_status.to_json)
|
||||
|
||||
described_class.new.execute
|
||||
expect(CustomWizard::Notice.list.length).to eq(2)
|
||||
end
|
||||
end
|
|
@ -1,11 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../plugin_helper'
|
||||
|
||||
describe Jobs::CustomWizardUpdateSubscription do
|
||||
it "updates the subscription" do
|
||||
stub_subscription_request(200, valid_subscription)
|
||||
described_class.new.execute
|
||||
expect(CustomWizard::Subscription.subscribed?).to eq(true)
|
||||
end
|
||||
end
|
|
@ -7,38 +7,3 @@ def get_wizard_fixture(path)
|
|||
).read
|
||||
).with_indifferent_access
|
||||
end
|
||||
|
||||
def authenticate_subscription
|
||||
CustomWizard::Subscription::Authentication.any_instance.stubs(:active?).returns(true)
|
||||
end
|
||||
|
||||
def enable_subscription(type)
|
||||
# CustomWizard::Subscription.new
|
||||
CustomWizard::Subscription.any_instance.stubs(:subscribed?).returns(true)
|
||||
CustomWizard::Subscription.any_instance.stubs(:type).returns(type)
|
||||
end
|
||||
|
||||
def disable_subscription
|
||||
CustomWizard::Subscription.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_subscription
|
||||
sub = CustomWizard::Subscription.new
|
||||
stub_request(:get, "https://#{sub.server}/subscription-server/user-subscriptions/#{sub.subscription_type}/#{sub.client_name}").to_return(status: status, body: { subscriptions: [subscription] }.to_json)
|
||||
end
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
require_relative '../../../plugin_helper'
|
||||
|
||||
describe CustomWizard::AdminNoticeController do
|
||||
fab!(:admin_user) { Fabricate(:user, admin: true) }
|
||||
let(:subscription_message_notice) {
|
||||
{
|
||||
title: "Title of message about subscription",
|
||||
message: "Message about subscription",
|
||||
type: 0,
|
||||
created_at: Time.now.iso8601(3),
|
||||
expired_at: nil
|
||||
}
|
||||
}
|
||||
let(:plugin_status_notice) {
|
||||
{
|
||||
title: "The Custom Wizard Plugin is incompatibile with the latest version of Discourse.",
|
||||
message: "Please check the Custom Wizard Plugin status on [localhost:3000](http://localhost:3000) before updating Discourse.",
|
||||
type: 1,
|
||||
archetype: 1,
|
||||
created_at: Time.now.iso8601(3),
|
||||
expired_at: nil
|
||||
}
|
||||
}
|
||||
|
||||
before do
|
||||
sign_in(admin_user)
|
||||
end
|
||||
|
||||
it "lists notices" do
|
||||
@notice = CustomWizard::Notice.new(subscription_message_notice)
|
||||
@notice.save
|
||||
|
||||
get "/admin/wizards/notice.json"
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body.length).to eq(1)
|
||||
end
|
||||
|
||||
it "dismisses notices" do
|
||||
@notice = CustomWizard::Notice.new(subscription_message_notice)
|
||||
@notice.save
|
||||
|
||||
put "/admin/wizards/notice/#{@notice.id}/dismiss.json"
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
updated = CustomWizard::Notice.find(@notice.id)
|
||||
expect(updated.dismissed?).to eq(true)
|
||||
end
|
||||
|
||||
it "dismisses all notices" do
|
||||
5.times do |index|
|
||||
subscription_message_notice[:title] += " #{index}"
|
||||
@notice = CustomWizard::Notice.new(subscription_message_notice)
|
||||
@notice.save
|
||||
end
|
||||
|
||||
put "/admin/wizards/notice/dismiss.json"
|
||||
expect(response.status).to eq(200)
|
||||
expect(CustomWizard::Notice.list.size).to eq(0)
|
||||
end
|
||||
|
||||
it "hides notices" do
|
||||
@notice = CustomWizard::Notice.new(plugin_status_notice)
|
||||
@notice.save
|
||||
|
||||
put "/admin/wizards/notice/#{@notice.id}/hide.json"
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
updated = CustomWizard::Notice.find(@notice.id)
|
||||
expect(updated.hidden?).to eq(true)
|
||||
end
|
||||
end
|
|
@ -1,71 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
require_relative '../../../plugin_helper'
|
||||
|
||||
describe CustomWizard::AdminSubscriptionController do
|
||||
fab!(:admin_user) { Fabricate(:user, admin: true) }
|
||||
|
||||
def generate_payload(request_id, user_id)
|
||||
uri = URI(@subscription.authentication_url(user_id, request_id))
|
||||
keys = @subscription.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
|
||||
@subscription = CustomWizard::Subscription.new
|
||||
sign_in(admin_user)
|
||||
end
|
||||
|
||||
it "#index" do
|
||||
get "/admin/wizards/subscription.json"
|
||||
expect(response.parsed_body['server']).to eq(@subscription.server)
|
||||
expect(response.parsed_body['authentication'].deep_symbolize_keys).to eq(CustomWizard::Subscription::AuthenticationSerializer.new(@subscription.authentication, root: false).as_json)
|
||||
expect(response.parsed_body['subscription'].deep_symbolize_keys).to eq(CustomWizard::Subscription::SubscriptionSerializer.new(@subscription.subscription, root: false).as_json)
|
||||
end
|
||||
|
||||
it "#authorize" do
|
||||
get "/admin/wizards/subscription/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)
|
||||
@subscription.authentication_response(request_id, payload)
|
||||
|
||||
delete "/admin/wizards/subscription/authorize.json"
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(CustomWizard::Subscription.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/subscription/authorize/callback", params: { payload: payload }
|
||||
|
||||
expect(response).to redirect_to("/admin/wizards/subscription")
|
||||
expect(CustomWizard::Subscription.subscribed?).to eq(true)
|
||||
end
|
||||
|
||||
it "updates the subscription" do
|
||||
authenticate_subscription
|
||||
post "/admin/wizards/subscription.json"
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(CustomWizard::Subscription.subscribed?).to eq(true)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,22 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../plugin_helper'
|
||||
|
||||
describe CustomWizard::NoticeSerializer do
|
||||
before do
|
||||
@notice = CustomWizard::Notice.new(
|
||||
message: "Message about subscription",
|
||||
type: "info",
|
||||
created_at: Time.now - 3.day,
|
||||
expired_at: nil
|
||||
)
|
||||
@notice.save
|
||||
end
|
||||
|
||||
it 'should return notice attributes' do
|
||||
serialized_notice = described_class.new(@notice)
|
||||
expect(serialized_notice.message).to eq(@notice.message)
|
||||
expect(serialized_notice.type).to eq(CustomWizard::Notice.types.key(@notice.type))
|
||||
expect(serialized_notice.dismissable).to eq(true)
|
||||
end
|
||||
end
|
|
@ -1,17 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../../plugin_helper'
|
||||
|
||||
describe CustomWizard::Subscription::AuthenticationSerializer do
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
|
||||
it 'should return subscription authentication attributes' do
|
||||
auth = CustomWizard::Subscription::Authentication.new(OpenStruct.new(key: '1234', auth_at: Time.now, auth_by: user.id))
|
||||
serialized = described_class.new(auth, root: false).as_json
|
||||
|
||||
expect(serialized[:active]).to eq(true)
|
||||
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
|
|
@ -1,14 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../../plugin_helper'
|
||||
|
||||
describe CustomWizard::Subscription::SubscriptionSerializer do
|
||||
it 'should return subscription attributes' do
|
||||
sub = CustomWizard::Subscription::Subscription.new(OpenStruct.new(type: 'standard', updated_at: Time.now))
|
||||
serialized = described_class.new(sub, root: false).as_json
|
||||
|
||||
expect(serialized[:active]).to eq(true)
|
||||
expect(serialized[:type]).to eq('standard')
|
||||
expect(serialized[:updated_at]).to eq(sub.updated_at)
|
||||
end
|
||||
end
|
|
@ -1,14 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../plugin_helper'
|
||||
|
||||
describe CustomWizard::SubscriptionSerializer do
|
||||
it 'should return subscription attributes' do
|
||||
subscription = CustomWizard::Subscription.new
|
||||
serialized = described_class.new(subscription, root: false)
|
||||
|
||||
expect(serialized.server).to eq(subscription.server)
|
||||
expect(serialized.authentication.class).to eq(CustomWizard::Subscription::Authentication)
|
||||
expect(serialized.subscription.class).to eq(CustomWizard::Subscription::Subscription)
|
||||
end
|
||||
end
|
Laden …
In neuem Issue referenzieren