Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-11-25 18:50:27 +01:00
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
|
before_action :ensure_admin
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
subcription = CustomWizard::Subscription.new
|
||||||
render_json_dump(
|
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
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
class CustomWizard::AdminCustomFieldsController < CustomWizard::AdminController
|
class CustomWizard::AdminCustomFieldsController < CustomWizard::AdminController
|
||||||
def index
|
def index
|
||||||
render_json_dump(
|
render_json_dump(
|
||||||
custom_fields: custom_field_list,
|
custom_fields: custom_field_list
|
||||||
subscribed: CustomWizard::Subscription.subscribed?,
|
|
||||||
subscription: CustomWizard::Subscription.type
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
||||||
),
|
),
|
||||||
field_types: CustomWizard::Field.types,
|
field_types: CustomWizard::Field.types,
|
||||||
realtime_validations: CustomWizard::RealtimeValidation.types,
|
realtime_validations: CustomWizard::RealtimeValidation.types,
|
||||||
custom_fields: custom_field_list,
|
custom_fields: custom_field_list
|
||||||
subscribed: CustomWizard::Subscription.subscribed?,
|
|
||||||
subscription: CustomWizard::Subscription.type
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -3,29 +3,6 @@ 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 I18n from "I18n";
|
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({
|
export default Component.extend({
|
||||||
tagName: "tr",
|
tagName: "tr",
|
||||||
topicSerializers: ["topic_view", "topic_list_item"],
|
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")
|
@observes("field.klass")
|
||||||
clearSerializersWhenClassChanges() {
|
clearSerializersWhenClassChanges() {
|
||||||
this.set("field.serializers", null);
|
this.set("field.serializers", null);
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
import { default as discourseComputed } from "discourse-common/utils/decorators";
|
||||||
import wizardSchema, {
|
import wizardSchema from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-schema";
|
||||||
requiringAdditionalSubscription,
|
import { subscriptionSelectKitContent } from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-subscription";
|
||||||
subscriptionLevel,
|
|
||||||
} from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-schema";
|
|
||||||
import { empty, equal, or } from "@ember/object/computed";
|
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";
|
||||||
|
@ -97,22 +95,8 @@ export default Component.extend(UndoChanges, {
|
||||||
return apis.find((a) => a.name === api).endpoints;
|
return apis.find((a) => a.name === api).endpoints;
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed("subscription")
|
@discourseComputed
|
||||||
actionTypes(subscription) {
|
actionTypes() {
|
||||||
let unsubscribedActions = requiringAdditionalSubscription(
|
return subscriptionSelectKitContent("action", "types");
|
||||||
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;
|
|
||||||
}, []);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -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 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"],
|
classNames: ["combo-box", "wizard-subscription-selector"],
|
||||||
|
|
||||||
selectKitOptions: {
|
selectKitOptions: {
|
||||||
|
@ -13,6 +28,38 @@ export default SingleSelectComponent.extend({
|
||||||
caretDownIcon: "caret-down",
|
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() {
|
modifyComponentForRow() {
|
||||||
return "wizard-subscription-selector/wizard-subscription-selector-row";
|
return "wizard-subscription-selector/wizard-subscription-selector-row";
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,11 +6,11 @@
|
||||||
</label>
|
</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
{{combo-box
|
{{combo-box
|
||||||
value=wizardListVal
|
value=wizardListVal
|
||||||
content=wizardList
|
content=wizardList
|
||||||
onChange=(action "changeWizard")
|
onChange=(action "changeWizard")
|
||||||
options=(hash
|
options=(hash
|
||||||
none="admin.wizard.select"
|
none="admin.wizard.select"
|
||||||
)}}
|
)}}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -14,6 +14,7 @@ import I18n from "I18n";
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
hasName: notEmpty("wizard.name"),
|
hasName: notEmpty("wizard.name"),
|
||||||
|
|
||||||
|
|
||||||
@observes("currentStep")
|
@observes("currentStep")
|
||||||
resetCurrentObjects() {
|
resetCurrentObjects() {
|
||||||
const currentStep = this.currentStep;
|
const currentStep = this.currentStep;
|
||||||
|
|
|
@ -1,26 +1,7 @@
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import { isPresent } from "@ember/utils";
|
import { equal } from "@ember/object/computed";
|
||||||
import { A } from "@ember/array";
|
|
||||||
|
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
adminWizardsNotices: controller(),
|
businessSubscription: equal('subscriptionType', 'business'),
|
||||||
|
standardSubscription: equal('subscriptionType', 'standard')
|
||||||
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();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -58,16 +58,6 @@ export default {
|
||||||
path: "/manager",
|
path: "/manager",
|
||||||
resetNamespace: true,
|
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"],
|
type: ["string", "boolean", "integer", "json"],
|
||||||
};
|
};
|
||||||
|
|
||||||
const subscription_levels = {
|
field.type = Object.keys(field.types);
|
||||||
standard: {
|
action.type = Object.keys(action.types);
|
||||||
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: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const wizardSchema = {
|
const wizardSchema = {
|
||||||
wizard,
|
wizard,
|
||||||
step,
|
step,
|
||||||
field,
|
field,
|
||||||
custom_field,
|
custom_field,
|
||||||
action,
|
action
|
||||||
subscription_levels,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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) {
|
export function buildFieldTypes(types) {
|
||||||
wizardSchema.field.types = 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) {
|
setupController(controller, model) {
|
||||||
const customFields = A(model.custom_fields || []);
|
const customFields = A(model.custom_fields || []);
|
||||||
const subscribed = model.subscribed;
|
|
||||||
const subscription = model.subscription;
|
|
||||||
|
|
||||||
controller.setProperties({
|
controller.setProperties({
|
||||||
customFields,
|
customFields
|
||||||
subscribed,
|
|
||||||
subscription,
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -38,9 +38,7 @@ export default DiscourseRoute.extend({
|
||||||
wizard,
|
wizard,
|
||||||
currentStep: wizard.steps[0],
|
currentStep: wizard.steps[0],
|
||||||
currentAction: wizard.actions[0],
|
currentAction: wizard.actions[0],
|
||||||
creating: model.create,
|
creating: model.create
|
||||||
subscribed: parentModel.subscribed,
|
|
||||||
subscription: parentModel.subscription,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
controller.setProperties(props);
|
controller.setProperties(props);
|
||||||
|
|
|
@ -7,21 +7,17 @@ export default DiscourseRoute.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
setupController(controller, model) {
|
setupController(controller, model) {
|
||||||
controller.set("api_section", model.api_section);
|
controller.setProperties({
|
||||||
|
subscribed: model.subscribed,
|
||||||
if (model.active_notice_count) {
|
subscriptionType: model.subscription_type,
|
||||||
controller.set("activeNoticeCount", model.active_notice_count);
|
subscriptionAttributes: model.subscription_attributes,
|
||||||
}
|
subscriptionClientInstalled: model.subscription_client_installed
|
||||||
if (model.featured_notices) {
|
});
|
||||||
controller.set("featuredNotices", model.featured_notices);
|
|
||||||
}
|
|
||||||
|
|
||||||
controller.subscribe();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
afterModel(model, transition) {
|
afterModel(model, transition) {
|
||||||
if (transition.targetName === "adminWizards.index") {
|
if (transition.targetName === "adminWizards.index") {
|
||||||
this.transitionTo("adminWizardsWizard");
|
this.transitionTo("adminWizardsWizard");
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -32,9 +32,7 @@
|
||||||
{{custom-field-input
|
{{custom-field-input
|
||||||
field=field
|
field=field
|
||||||
removeField=(action "removeField")
|
removeField=(action "removeField")
|
||||||
saveField=(action "saveField")
|
saveField=(action "saveField")}}
|
||||||
subscribed=subscribed
|
|
||||||
subscription=subscription}}
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -126,7 +126,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#subscription-container subscribed=subscribed}}
|
{{#wizard-subscription-container}}
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<label>{{i18n "admin.wizard.save_submissions"}}</label>
|
<label>{{i18n "admin.wizard.save_submissions"}}</label>
|
||||||
|
@ -146,7 +146,7 @@
|
||||||
<span>{{i18n "admin.wizard.restart_on_revisit_label"}}</span>
|
<span>{{i18n "admin.wizard.restart_on_revisit_label"}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/subscription-container}}
|
{{/wizard-subscription-container}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{wizard-links
|
{{wizard-links
|
||||||
|
@ -177,9 +177,7 @@
|
||||||
wizard=wizard
|
wizard=wizard
|
||||||
apis=apis
|
apis=apis
|
||||||
removeAction="removeAction"
|
removeAction="removeAction"
|
||||||
wizardFields=wizardFields
|
wizardFields=wizardFields}}
|
||||||
subscribed=subscribed
|
|
||||||
subscription=subscription}}
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
<div class="admin-wizard-buttons">
|
<div class="admin-wizard-buttons">
|
||||||
|
|
|
@ -2,13 +2,14 @@
|
||||||
{{nav-item route="adminWizardsWizard" label="admin.wizard.nav_label"}}
|
{{nav-item route="adminWizardsWizard" label="admin.wizard.nav_label"}}
|
||||||
{{nav-item route="adminWizardsCustomFields" label="admin.wizard.custom_field.nav_label"}}
|
{{nav-item route="adminWizardsCustomFields" label="admin.wizard.custom_field.nav_label"}}
|
||||||
{{nav-item route="adminWizardsSubmissions" label="admin.wizard.submissions.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"}}
|
{{nav-item route="adminWizardsApi" label="admin.wizard.api.nav_label"}}
|
||||||
{{/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"}}
|
||||||
|
|
||||||
<div class="admin-actions">
|
<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"}}>
|
<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"}}
|
{{d-icon "far-life-ring"}}{{i18n "admin.wizard.support_button.label"}}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -2,16 +2,22 @@
|
||||||
<td>
|
<td>
|
||||||
{{wizard-subscription-selector
|
{{wizard-subscription-selector
|
||||||
value=field.klass
|
value=field.klass
|
||||||
content=customFieldKlasses
|
feature="custom_field"
|
||||||
none="admin.wizard.custom_field.klass.select"
|
attribute="klass"
|
||||||
onChange=(action (mut field.klass))}}
|
onChange=(action (mut field.klass))
|
||||||
|
options=(hash
|
||||||
|
none="admin.wizard.custom_field.klass.select"
|
||||||
|
)}}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{wizard-subscription-selector
|
{{wizard-subscription-selector
|
||||||
value=field.type
|
value=field.type
|
||||||
content=customFieldTypes
|
feature="custom_field"
|
||||||
none="admin.wizard.custom_field.type.select"
|
attribute="type"
|
||||||
onChange=(action (mut field.type))}}
|
onChange=(action (mut field.type))
|
||||||
|
options=(hash
|
||||||
|
none="admin.wizard.custom_field.type.select"
|
||||||
|
)}}
|
||||||
</td>
|
</td>
|
||||||
<td class="input">
|
<td class="input">
|
||||||
{{input
|
{{input
|
||||||
|
@ -22,8 +28,10 @@
|
||||||
{{multi-select
|
{{multi-select
|
||||||
value=field.serializers
|
value=field.serializers
|
||||||
content=serializerContent
|
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>
|
||||||
<td class="actions">
|
<td class="actions">
|
||||||
{{#if loading}}
|
{{#if loading}}
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{wizard-subscription-selector
|
{{wizard-subscription-selector
|
||||||
value=action.type
|
value=action.type
|
||||||
content=actionTypes
|
feature="action"
|
||||||
|
attribute="type"
|
||||||
onChange=(action "changeType")
|
onChange=(action "changeType")
|
||||||
options=(hash
|
options=(hash
|
||||||
none="admin.wizard.select_type"
|
none="admin.wizard.select_type"
|
||||||
|
|
|
@ -222,7 +222,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#subscription-container subscribed=subscribed}}
|
{{#wizard-subscription-container}}
|
||||||
<div class="setting full field-mapper-setting">
|
<div class="setting full field-mapper-setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<label>{{i18n "admin.wizard.condition"}}</label>
|
<label>{{i18n "admin.wizard.condition"}}</label>
|
||||||
|
@ -237,7 +237,7 @@
|
||||||
|
|
||||||
<div class="setting full field-mapper-setting">
|
<div class="setting full field-mapper-setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<label>{{i18n "admin.wizard.index"}}</label>>
|
<label>{{i18n "admin.wizard.index"}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
|
@ -248,10 +248,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if isCategory}}
|
{{#if isCategory}}
|
||||||
<div class="setting pro">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<label>{{i18n "admin.wizard.field.property"}}</label>
|
<label>{{i18n "admin.wizard.field.property"}}</label>
|
||||||
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
|
@ -269,4 +268,4 @@
|
||||||
{{#if validations}}
|
{{#if validations}}
|
||||||
{{wizard-realtime-validations field=field validations=validations}}
|
{{wizard-realtime-validations field=field validations=validations}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/subscription-container}}
|
{{/wizard-subscription-container}}
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#subscription-container subscribed=subscribed}}
|
{{#wizard-subscription-container}}
|
||||||
<div class="setting full field-mapper-setting">
|
<div class="setting full field-mapper-setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<label>{{i18n "admin.wizard.condition"}}</label>
|
<label>{{i18n "admin.wizard.condition"}}</label>
|
||||||
|
@ -56,11 +56,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting full field-mapper-setting pro">
|
<div class="setting full field-mapper-setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<label>{{i18n "admin.wizard.step.required_data.label"}}</label>
|
<label>{{i18n "admin.wizard.step.required_data.label"}}</label>
|
||||||
<span class="pro-label">{{i18n "admin.wizard.pro.label"}}</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{wizard-mapper
|
{{wizard-mapper
|
||||||
inputs=step.required_data
|
inputs=step.required_data
|
||||||
|
@ -99,7 +99,7 @@
|
||||||
)}}
|
)}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/subscription-container}}
|
{{/wizard-subscription-container}}
|
||||||
|
|
||||||
{{wizard-links
|
{{wizard-links
|
||||||
itemType="field"
|
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">
|
<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}}
|
{{d-icon subscribedIcon}}
|
||||||
{{i18n subscribedLabel}}
|
{{i18n subscribedLabel}}
|
||||||
</a>
|
</a>
|
|
@ -7,8 +7,10 @@
|
||||||
shouldDisplayClearableButton=shouldDisplayClearableButton
|
shouldDisplayClearableButton=shouldDisplayClearableButton
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{{#if selectedContent.subscription}}
|
{{#if selectedContent.subscriptionType}}
|
||||||
<span class="subscription-label">{{i18n "admin.wizard.subscription.label"}}</span>
|
<span class="subscription-label">
|
||||||
|
{{selectedContent.subscriptionType}}
|
||||||
|
</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{d-icon caretIcon class="caret-icon"}}
|
{{d-icon caretIcon class="caret-icon"}}
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
|
|
||||||
<div class="texts">
|
<div class="texts">
|
||||||
<span class="name">{{html-safe label}}</span>
|
<span class="name">{{html-safe label}}</span>
|
||||||
{{#if item.subscription}}
|
{{#if item.subscriptionType}}
|
||||||
<span class="subscription-label">
|
<span class="subscription-label">
|
||||||
{{item.subscription}}
|
{{item.subscriptionType}}
|
||||||
</span>
|
</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -25,6 +25,14 @@ $error: #ef1700;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.admin-wizards .admin-actions {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.btn-pavilion-support {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.wizard-message {
|
.wizard-message {
|
||||||
background-color: var(--primary-low);
|
background-color: var(--primary-low);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -156,6 +164,16 @@ $error: #ef1700;
|
||||||
@extend .wizard-settings-group;
|
@extend .wizard-settings-group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.admin-wizard-container.settings {
|
||||||
|
.wizard-settings {
|
||||||
|
.wizard-subscription-container {
|
||||||
|
[class~="setting"] {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.wizard-custom-field {
|
.wizard-custom-field {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
background-color: var(--primary-very-low);
|
background-color: var(--primary-very-low);
|
||||||
|
@ -802,84 +820,6 @@ $error: #ef1700;
|
||||||
vertical-align: middle;
|
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 {
|
.btn.btn-pavilion-support {
|
||||||
background: var(--pavilion-primary);
|
background: var(--pavilion-primary);
|
||||||
color: var(--pavilion-secondary);
|
color: var(--pavilion-secondary);
|
||||||
|
@ -899,7 +839,7 @@ $error: #ef1700;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.subscription-container {
|
.wizard-subscription-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
background-color: rgba($pavilion_primary, 0.1);
|
background-color: rgba($pavilion_primary, 0.1);
|
||||||
|
@ -907,158 +847,79 @@ $error: #ef1700;
|
||||||
.subscription-header {
|
.subscription-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-bottom: 1em;
|
margin-bottom: .25em;
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: var(--pavilion-primary);
|
color: var(--primary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.subscribed) .subscription-settings {
|
&:not(.subscribed) .subscription-settings {
|
||||||
filter: blur(1px);
|
filter: blur(1px);
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-wizards-notices {
|
.wizard-subscription-badge {
|
||||||
.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 {
|
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-height: 25px;
|
max-height: 34px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: var(--primary) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.admin-actions {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wizard-notices-link {
|
|
||||||
position: relative;
|
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 {
|
&:hover {
|
||||||
@include btn;
|
color: $primary-medium;
|
||||||
color: var(--secondary) !important;
|
}
|
||||||
background-color: var(--primary-medium);
|
|
||||||
|
|
||||||
&.active {
|
svg {
|
||||||
background-color: var(--tertiary) !important;
|
width: 15px;
|
||||||
color: var(--secondary) !important;
|
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 {
|
.subscription-label {
|
||||||
background-color: $danger;
|
margin-left: 0.75em;
|
||||||
color: $secondary;
|
padding-top: 0.25em;
|
||||||
border-radius: 50%;
|
color: var(--pavilion-primary);
|
||||||
width: 18px;
|
font-size: 0.75em;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,13 @@ $pavilion_primary: #3c1c8c;
|
||||||
$pavilion_secondary: #ffffff;
|
$pavilion_secondary: #ffffff;
|
||||||
$pavilion_warning: rgb(243, 163, 61);
|
$pavilion_warning: rgb(243, 163, 61);
|
||||||
|
|
||||||
|
$subscription_standard: $pavilion_primary;
|
||||||
|
$subscription_business: #333;
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--pavilion-primary: #{$pavilion_primary};
|
--pavilion-primary: #{$pavilion_primary};
|
||||||
--pavilion-secondary: #{$pavilion_secondary};
|
--pavilion-secondary: #{$pavilion_secondary};
|
||||||
--pavilion-warning: #{$pavilion_warning};
|
--pavilion-warning: #{$pavilion_warning};
|
||||||
|
--subscription-standard: #{$subscription_standard};
|
||||||
|
--subscription-business: #{$subscription_business};
|
||||||
}
|
}
|
||||||
|
|
|
@ -474,53 +474,16 @@ en:
|
||||||
not_subscribed:
|
not_subscribed:
|
||||||
label: Not Subscribed
|
label: Not Subscribed
|
||||||
title: Subscribe to use these features
|
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:
|
type:
|
||||||
label: Type
|
none:
|
||||||
info: Information
|
label: Not Subscribed
|
||||||
warning: Warning
|
title: There is no Custom Wizard subscription active on this forum.
|
||||||
connection_error: Connection Error
|
business:
|
||||||
|
label: Business
|
||||||
notices:
|
title: There is a Custom Wizard Business subscription active on this forum.
|
||||||
nav_label: Notices
|
standard:
|
||||||
title: Plugin Notices
|
label: Standard
|
||||||
|
title: There is a Custom Wizard Standard subscription active on this forum.
|
||||||
|
|
||||||
wizard_js:
|
wizard_js:
|
||||||
group:
|
group:
|
||||||
|
|
|
@ -84,7 +84,7 @@ class ::CustomWizard::CustomField
|
||||||
next
|
next
|
||||||
end
|
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))
|
add_error(I18n.t("wizard.custom_field.error.subscription_type", type: value))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ 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' && @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))
|
add_error(I18n.t("wizard.custom_field.error.subscription_type", type: value))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,6 @@ class CustomWizard::Mapper
|
||||||
@data = params[:data] || {}
|
@data = params[:data] || {}
|
||||||
@user = params[:user]
|
@user = params[:user]
|
||||||
@opts = params[:opts] || {}
|
@opts = params[:opts] || {}
|
||||||
@subscription = CustomWizard::Subscription.new
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
@ -252,7 +251,7 @@ class CustomWizard::Mapper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if opts[:template] && @subscription.subscribed?
|
if opts[:template] && CustomWizard::Subscription.subscribed?
|
||||||
template = Liquid::Template.parse(string)
|
template = Liquid::Template.parse(string)
|
||||||
string = template.render(data)
|
string = template.render(data)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,8 +1,170 @@
|
||||||
class CustomWizard::Subscription
|
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?
|
def self.subscribed?
|
||||||
|
new.subscribed?
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.business?
|
||||||
|
new.business?
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.standard?
|
||||||
|
new.standard?
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.type
|
def self.type
|
||||||
|
new.type
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -56,29 +56,10 @@ class CustomWizard::TemplateValidator
|
||||||
|
|
||||||
def self.subscription
|
def self.subscription
|
||||||
{
|
{
|
||||||
wizard: {
|
wizard: ['save_submissions', 'restart_on_revisit'],
|
||||||
save_submissions: 'false',
|
step: ['condition', 'index', 'required_data', 'permitted_params'],
|
||||||
restart_on_revisit: 'true',
|
field: ['condition', 'index'],
|
||||||
},
|
action: ['type']
|
||||||
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
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -93,16 +74,8 @@ class CustomWizard::TemplateValidator
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_subscription(object, type)
|
def validate_subscription(object, type)
|
||||||
self.class.subscription[type].each do |property, subscription_type|
|
self.class.subscription[type].each do |property|
|
||||||
val = object[property.to_s]
|
if !@subscription.includes?(type, property, object[property])
|
||||||
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?
|
|
||||||
errors.add :base, I18n.t("wizard.validation.subscription", type: type.to_s, property: property)
|
errors.add :base, I18n.t("wizard.validation.subscription", type: type.to_s, property: property)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -148,10 +121,6 @@ class CustomWizard::TemplateValidator
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_bool(val)
|
|
||||||
ActiveRecord::Type::Boolean.new.cast(val)
|
|
||||||
end
|
|
||||||
|
|
||||||
def validate_liquid_template(object, type)
|
def validate_liquid_template(object, type)
|
||||||
%w[
|
%w[
|
||||||
description
|
description
|
||||||
|
|
25
plugin.rb
25
plugin.rb
|
@ -5,17 +5,13 @@
|
||||||
# authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George
|
# authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George
|
||||||
# contact_emails: support@thepavilion.io
|
# contact_emails: support@thepavilion.io
|
||||||
# url: https://github.com/paviliondev/discourse-custom-wizard
|
# url: https://github.com/paviliondev/discourse-custom-wizard
|
||||||
|
# subscription_url: https://coop.pavilion.tech
|
||||||
|
|
||||||
gem 'liquid', '5.0.1', require: true
|
gem 'liquid', '5.0.1', require: true
|
||||||
register_asset 'stylesheets/admin/admin.scss', :desktop
|
register_asset 'stylesheets/admin/admin.scss', :desktop
|
||||||
|
|
||||||
enabled_site_setting :custom_wizard_enabled
|
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?
|
if Rails.env.production?
|
||||||
config.assets.precompile += %w{
|
config.assets.precompile += %w{
|
||||||
wizard-custom-guest.js
|
wizard-custom-guest.js
|
||||||
|
@ -59,6 +55,24 @@ class ::Sprockets::DirectiveProcessor
|
||||||
end
|
end
|
||||||
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
|
after_initialize do
|
||||||
%w[
|
%w[
|
||||||
../lib/custom_wizard/engine.rb
|
../lib/custom_wizard/engine.rb
|
||||||
|
@ -91,6 +105,7 @@ after_initialize do
|
||||||
../lib/custom_wizard/step_updater.rb
|
../lib/custom_wizard/step_updater.rb
|
||||||
../lib/custom_wizard/step.rb
|
../lib/custom_wizard/step.rb
|
||||||
../lib/custom_wizard/submission.rb
|
../lib/custom_wizard/submission.rb
|
||||||
|
../lib/custom_wizard/subscription.rb
|
||||||
../lib/custom_wizard/template.rb
|
../lib/custom_wizard/template.rb
|
||||||
../lib/custom_wizard/wizard.rb
|
../lib/custom_wizard/wizard.rb
|
||||||
../lib/custom_wizard/api/api.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
|
).read
|
||||||
).with_indifferent_access
|
).with_indifferent_access
|
||||||
end
|
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