Remove subs and notices files
Dieser Commit ist enthalten in:
Ursprung
c0b93fc166
Commit
5edfb4c41e
40 geänderte Dateien mit 17 neuen und 1826 gelöschten Zeilen
|
@ -4,16 +4,7 @@ class CustomWizard::AdminController < ::Admin::AdminController
|
|||
|
||||
def index
|
||||
render_json_dump(
|
||||
#TODO replace with appropriate static?
|
||||
api_section: ["business"].include?(CustomWizard::Subscription.type),
|
||||
active_notice_count: CustomWizard::Notice.active_count,
|
||||
featured_notices: ActiveModel::ArraySerializer.new(
|
||||
CustomWizard::Notice.list(
|
||||
type: CustomWizard::Notice.types[:info],
|
||||
archetype: CustomWizard::Notice.archetypes[:subscription_message]
|
||||
),
|
||||
each_serializer: CustomWizard::NoticeSerializer
|
||||
)
|
||||
api_section: ["business"].include?(CustomWizard::Subscription.type)
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CustomWizard::AdminNoticeController < CustomWizard::AdminController
|
||||
before_action :find_notice, only: [:dismiss, :hide]
|
||||
|
||||
def index
|
||||
type = params[:type]
|
||||
archetype = params[:archtype]
|
||||
page = params[:page].to_i
|
||||
include_all = ActiveRecord::Type::Boolean.new.cast(params[:include_all])
|
||||
visible = ActiveRecord::Type::Boolean.new.cast(params[:visible])
|
||||
|
||||
if type
|
||||
if type.is_a?(Array)
|
||||
type = type.map { |t| CustomWizard::Notice.types[t.to_sym] }
|
||||
else
|
||||
type = CustomWizard::Notice.types[type.to_sym]
|
||||
end
|
||||
end
|
||||
|
||||
if archetype
|
||||
if archetype.is_a?(Array)
|
||||
archetype = archetype.map { |t| CustomWizard::Notice.archetypes[archetype.to_sym] }
|
||||
else
|
||||
archetype = CustomWizard::Notice.archetypes[archetype.to_sym]
|
||||
end
|
||||
end
|
||||
|
||||
notices = CustomWizard::Notice.list(
|
||||
include_all: include_all,
|
||||
page: page,
|
||||
type: type,
|
||||
archetype: archetype,
|
||||
visible: visible
|
||||
)
|
||||
|
||||
render_serialized(notices, CustomWizard::NoticeSerializer, root: :notices)
|
||||
end
|
||||
|
||||
def dismiss
|
||||
if @notice.dismissable? && @notice.dismiss!
|
||||
render json: success_json.merge(dismissed_at: @notice.dismissed_at)
|
||||
else
|
||||
render json: failed_json
|
||||
end
|
||||
end
|
||||
|
||||
def hide
|
||||
if @notice.can_hide? && @notice.hide!
|
||||
render json: success_json.merge(hidden_at: @notice.hidden_at)
|
||||
else
|
||||
render json: failed_json
|
||||
end
|
||||
end
|
||||
|
||||
def dismiss_all
|
||||
if CustomWizard::Notice.dismiss_all
|
||||
render json: success_json
|
||||
else
|
||||
render json: failed_json
|
||||
end
|
||||
end
|
||||
|
||||
def find_notice
|
||||
@notice = CustomWizard::Notice.find(params[:notice_id])
|
||||
raise Discourse::InvalidParameters.new(:notice_id) unless @notice
|
||||
end
|
||||
end
|
|
@ -1,48 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CustomWizard::AdminSubscriptionController < CustomWizard::AdminController
|
||||
skip_before_action :check_xhr, :preload_json, :verify_authenticity_token, only: [:authorize, :authorize_callback]
|
||||
|
||||
def index
|
||||
render_serialized(subscription, CustomWizard::SubscriptionSerializer, root: false)
|
||||
end
|
||||
|
||||
def authorize
|
||||
request_id = SecureRandom.hex(32)
|
||||
cookies[:user_api_request_id] = request_id
|
||||
redirect_to subscription.authentication_url(current_user.id, request_id).to_s
|
||||
end
|
||||
|
||||
def authorize_callback
|
||||
payload = params[:payload]
|
||||
request_id = cookies[:user_api_request_id]
|
||||
|
||||
subscription.authentication_response(request_id, payload)
|
||||
subscription.update
|
||||
|
||||
redirect_to '/admin/wizards/subscription'
|
||||
end
|
||||
|
||||
def destroy_authentication
|
||||
if subscription.destroy_authentication
|
||||
render json: success_json
|
||||
else
|
||||
render json: failed_json
|
||||
end
|
||||
end
|
||||
|
||||
def update_subscription
|
||||
if subscription.update
|
||||
serialized_subscription = CustomWizard::Subscription::SubscriptionSerializer.new(subscription.subscription, root: false)
|
||||
render json: success_json.merge(subscription: serialized_subscription)
|
||||
else
|
||||
render json: failed_json
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def subscription
|
||||
@subscription ||= CustomWizard::Subscription.new
|
||||
end
|
||||
end
|
|
@ -11,7 +11,6 @@ class CustomWizard::WizardController < ::ActionController::Base
|
|||
|
||||
before_action :preload_wizard_json
|
||||
before_action :ensure_plugin_enabled
|
||||
before_action :update_subscription, only: [:index]
|
||||
before_action :ensure_logged_in, only: [:skip]
|
||||
|
||||
helper_method :wizard_page_title
|
||||
|
@ -123,8 +122,4 @@ class CustomWizard::WizardController < ::ActionController::Base
|
|||
redirect_to path("/")
|
||||
end
|
||||
end
|
||||
|
||||
def update_subscription
|
||||
CustomWizard::Subscription.update
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Jobs::CustomWizardUpdateNotices < ::Jobs::Scheduled
|
||||
every 5.minutes
|
||||
|
||||
def execute(args = {})
|
||||
CustomWizard::Notice.update
|
||||
end
|
||||
end
|
|
@ -1,9 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Jobs::CustomWizardUpdateSubscription < ::Jobs::Scheduled
|
||||
every 1.hour
|
||||
|
||||
def execute(args = {})
|
||||
CustomWizard::Subscription.update
|
||||
end
|
||||
end
|
|
@ -1,33 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CustomWizard::NoticeSerializer < ApplicationSerializer
|
||||
attributes :id,
|
||||
:title,
|
||||
:message,
|
||||
:type,
|
||||
:archetype,
|
||||
:created_at,
|
||||
:expired_at,
|
||||
:updated_at,
|
||||
:dismissed_at,
|
||||
:retrieved_at,
|
||||
:hidden_at,
|
||||
:dismissable,
|
||||
:can_hide
|
||||
|
||||
def dismissable
|
||||
object.dismissable?
|
||||
end
|
||||
|
||||
def can_hide
|
||||
object.can_hide?
|
||||
end
|
||||
|
||||
def type
|
||||
CustomWizard::Notice.types.key(object.type)
|
||||
end
|
||||
|
||||
def messsage
|
||||
PrettyText.cook(object.message)
|
||||
end
|
||||
end
|
|
@ -1,11 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
class CustomWizard::Subscription::AuthenticationSerializer < ApplicationSerializer
|
||||
attributes :active,
|
||||
:client_id,
|
||||
:auth_by,
|
||||
:auth_at
|
||||
|
||||
def active
|
||||
object.active?
|
||||
end
|
||||
end
|
|
@ -1,10 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
class CustomWizard::Subscription::SubscriptionSerializer < ApplicationSerializer
|
||||
attributes :type,
|
||||
:active,
|
||||
:updated_at
|
||||
|
||||
def active
|
||||
object.active?
|
||||
end
|
||||
end
|
|
@ -1,6 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
class CustomWizard::SubscriptionSerializer < ApplicationSerializer
|
||||
attributes :server
|
||||
has_one :authentication, serializer: CustomWizard::Subscription::AuthenticationSerializer, embed: :objects
|
||||
has_one :subscription, serializer: CustomWizard::Subscription::SubscriptionSerializer, embed: :objects
|
||||
end
|
|
@ -1,25 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: [":subscription-container", "subscribed"],
|
||||
|
||||
@discourseComputed("subscribed")
|
||||
subscribedIcon(subscribed) {
|
||||
return subscribed ? "check" : "dash";
|
||||
},
|
||||
|
||||
@discourseComputed("subscribed")
|
||||
subscribedLabel(subscribed) {
|
||||
return `admin.wizard.subscription_container.${
|
||||
subscribed ? "subscribed" : "not_subscribed"
|
||||
}.label`;
|
||||
},
|
||||
|
||||
@discourseComputed("subscribed")
|
||||
subscribedTitle(subscribed) {
|
||||
return `admin.wizard.subscription_container.${
|
||||
subscribed ? "subscribed" : "not_subscribed"
|
||||
}.title`;
|
||||
},
|
||||
});
|
|
@ -1,19 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
import NoticeMessage from "../mixins/notice-message";
|
||||
|
||||
export default Component.extend(NoticeMessage, {
|
||||
tagName: "tr",
|
||||
attributeBindings: ["notice.id:data-notice-id"],
|
||||
classNameBindings: [
|
||||
":wizard-notice-row",
|
||||
"notice.typeClass",
|
||||
"notice.expired:expired",
|
||||
"notice.dismissed:dismissed",
|
||||
],
|
||||
|
||||
actions: {
|
||||
dismiss() {
|
||||
this.notice.dismiss();
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,29 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
import NoticeMessage from "../mixins/notice-message";
|
||||
|
||||
export default Component.extend(NoticeMessage, {
|
||||
attributeBindings: ["notice.id:data-notice-id"],
|
||||
classNameBindings: [
|
||||
":wizard-notice",
|
||||
"notice.typeClass",
|
||||
"notice.dismissed:dismissed",
|
||||
"notice.expired:expired",
|
||||
"notice.hidden:hidden",
|
||||
],
|
||||
|
||||
actions: {
|
||||
dismiss() {
|
||||
this.set("dismissing", true);
|
||||
this.notice.dismiss().then(() => {
|
||||
this.set("dismissing", false);
|
||||
});
|
||||
},
|
||||
|
||||
hide() {
|
||||
this.set("hiding", true);
|
||||
this.notice.hide().then(() => {
|
||||
this.set("hiding", false);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,55 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
import CustomWizardSubscription from "../models/custom-wizard-subscription";
|
||||
import { notEmpty } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: [
|
||||
":custom-wizard-subscription",
|
||||
"subscription.active:active:inactive",
|
||||
],
|
||||
subscribed: notEmpty("subscription"),
|
||||
|
||||
@discourseComputed("subscription.type")
|
||||
title(type) {
|
||||
return type
|
||||
? I18n.t(`admin.wizard.subscription.subscription.title.${type}`)
|
||||
: I18n.t("admin.wizard.subscription.not_subscribed");
|
||||
},
|
||||
|
||||
@discourseComputed("subscription.active")
|
||||
stateClass(active) {
|
||||
return active ? "active" : "inactive";
|
||||
},
|
||||
|
||||
@discourseComputed("stateClass")
|
||||
stateLabel(stateClass) {
|
||||
return I18n.t(
|
||||
`admin.wizard.subscription.subscription.status.${stateClass}`
|
||||
);
|
||||
},
|
||||
|
||||
actions: {
|
||||
update() {
|
||||
this.set("updating", true);
|
||||
CustomWizardSubscription.update()
|
||||
.then((result) => {
|
||||
if (result.success) {
|
||||
this.setProperties({
|
||||
updateIcon: "check",
|
||||
subscription: result.subscription,
|
||||
});
|
||||
} else {
|
||||
this.set("updateIcon", "times");
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.set("updating", false);
|
||||
setTimeout(() => {
|
||||
this.set("updateIcon", null);
|
||||
}, 7000);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,5 +0,0 @@
|
|||
{{#if notices}}
|
||||
{{#each notices as |notice|}}
|
||||
{{wizard-notice notice=notice showPlugin=true}}
|
||||
{{/each}}
|
||||
{{/if}}
|
|
@ -1,19 +0,0 @@
|
|||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
|
||||
export default {
|
||||
shouldRender(attrs, ctx) {
|
||||
return ctx.siteSettings.wizard_critical_notices_on_dashboard;
|
||||
},
|
||||
|
||||
setupComponent(attrs, component) {
|
||||
const controller = getOwner(this).lookup("controller:admin-dashboard");
|
||||
|
||||
component.set("notices", controller.get("customWizardCriticalNotices"));
|
||||
controller.addObserver("customWizardCriticalNotices.[]", () => {
|
||||
if (this._state === "destroying") {
|
||||
return;
|
||||
}
|
||||
component.set("notices", controller.get("customWizardCriticalNotices"));
|
||||
});
|
||||
},
|
||||
};
|
|
@ -1,68 +0,0 @@
|
|||
import Controller from "@ember/controller";
|
||||
import CustomWizardNotice from "../models/custom-wizard-notice";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { notEmpty } from "@ember/object/computed";
|
||||
import { A } from "@ember/array";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Controller.extend({
|
||||
messageUrl: "https://thepavilion.io/t/3652",
|
||||
messageKey: "info",
|
||||
messageIcon: "info-circle",
|
||||
messageClass: "info",
|
||||
hasNotices: notEmpty("notices"),
|
||||
page: 0,
|
||||
loadingMore: false,
|
||||
canLoadMore: true,
|
||||
|
||||
@discourseComputed("notices.[]", "notices.@each.dismissed")
|
||||
allDismisssed(notices) {
|
||||
return notices.every((n) => !n.canDismiss || n.dismissed);
|
||||
},
|
||||
|
||||
loadMoreNotices() {
|
||||
if (!this.canLoadMore) {
|
||||
return;
|
||||
}
|
||||
const page = this.get("page");
|
||||
this.set("loadingMore", true);
|
||||
|
||||
CustomWizardNotice.list({ page, include_all: true })
|
||||
.then((result) => {
|
||||
if (result.notices.length === 0) {
|
||||
this.set("canLoadMore", false);
|
||||
return;
|
||||
}
|
||||
|
||||
this.get("notices").pushObjects(
|
||||
A(result.notices.map((notice) => CustomWizardNotice.create(notice)))
|
||||
);
|
||||
})
|
||||
.finally(() => this.set("loadingMore", false));
|
||||
},
|
||||
|
||||
actions: {
|
||||
loadMore() {
|
||||
if (this.canLoadMore) {
|
||||
this.set("page", this.page + 1);
|
||||
this.loadMoreNotices();
|
||||
}
|
||||
},
|
||||
|
||||
dismissAll() {
|
||||
bootbox.confirm(
|
||||
I18n.t("admin.wizard.notice.dismiss_all.confirm"),
|
||||
I18n.t("no_value"),
|
||||
I18n.t("yes_value"),
|
||||
(result) => {
|
||||
if (result) {
|
||||
this.set("loadingMore", true);
|
||||
CustomWizardNotice.dismissAll().finally(() =>
|
||||
this.set("loadingMore", false)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,62 +0,0 @@
|
|||
import Controller from "@ember/controller";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import CustomWizardSubscription from "../models/custom-wizard-subscription";
|
||||
import { alias } from "@ember/object/computed";
|
||||
|
||||
export default Controller.extend({
|
||||
messageUrl: "https://thepavilion.io/t/3652",
|
||||
messageType: "info",
|
||||
messageKey: null,
|
||||
showSubscription: alias("model.authentication.active"),
|
||||
|
||||
setup() {
|
||||
const authentication = this.get("model.authentication");
|
||||
const subscription = this.get("model.subscription");
|
||||
const subscribed = subscription && subscription.active;
|
||||
const authenticated = authentication && authentication.active;
|
||||
|
||||
if (!subscribed) {
|
||||
this.set("messageKey", authenticated ? "not_subscribed" : "authorize");
|
||||
} else {
|
||||
this.set(
|
||||
"messageKey",
|
||||
!authenticated
|
||||
? "subscription_expiring"
|
||||
: subscribed
|
||||
? "subscription_active"
|
||||
: "subscription_inactive"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.server")
|
||||
messageOpts(server) {
|
||||
return { server };
|
||||
},
|
||||
|
||||
actions: {
|
||||
unauthorize() {
|
||||
this.set("unauthorizing", true);
|
||||
|
||||
CustomWizardSubscription.unauthorize()
|
||||
.then((result) => {
|
||||
if (result.success) {
|
||||
this.setProperties({
|
||||
messageKey: "unauthorized",
|
||||
messageType: "warn",
|
||||
"model.authentication": null,
|
||||
"model.subscription": null,
|
||||
});
|
||||
} else {
|
||||
this.setProperties({
|
||||
messageKey: "unauthorize_failed",
|
||||
messageType: "error",
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.set("unauthorizing", false);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,43 +0,0 @@
|
|||
import { autoUpdatingRelativeAge } from "discourse/lib/formatter";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
import I18n from "I18n";
|
||||
import { registerUnbound } from "discourse-common/lib/helpers";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
|
||||
registerUnbound("notice-badge", function (attrs) {
|
||||
let tag = attrs.url ? "a" : "div";
|
||||
let attrStr = "";
|
||||
if (attrs.title) {
|
||||
attrStr += `title='${I18n.t(attrs.title)}'`;
|
||||
}
|
||||
if (attrs.url) {
|
||||
attrStr += `href='${attrs.url}'`;
|
||||
}
|
||||
let html = `<${tag} class="${
|
||||
attrs.class ? `${attrs.class} ` : ""
|
||||
}notice-badge" ${attrStr}>`;
|
||||
if (attrs.icon) {
|
||||
html += iconHTML(attrs.icon);
|
||||
}
|
||||
if (attrs.label) {
|
||||
if (attrs.icon) {
|
||||
html += " ";
|
||||
}
|
||||
html += `<span>${I18n.t(attrs.label)}</span>`;
|
||||
}
|
||||
if (attrs.date) {
|
||||
if (attrs.icon || attrs.label) {
|
||||
html += " ";
|
||||
}
|
||||
let dateAttrs = {};
|
||||
if (attrs.leaveAgo) {
|
||||
dateAttrs = {
|
||||
format: "medium",
|
||||
leaveAgo: true,
|
||||
};
|
||||
}
|
||||
html += autoUpdatingRelativeAge(new Date(attrs.date), dateAttrs);
|
||||
}
|
||||
html += `</${tag}>`;
|
||||
return htmlSafe(html);
|
||||
});
|
|
@ -1,6 +1,5 @@
|
|||
import DiscourseURL from "discourse/lib/url";
|
||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
import CustomWizardNotice from "../models/custom-wizard-notice";
|
||||
import { isPresent } from "@ember/utils";
|
||||
import { A } from "@ember/array";
|
||||
import getUrl from "discourse-common/lib/get-url";
|
||||
|
@ -23,50 +22,6 @@ export default {
|
|||
};
|
||||
|
||||
withPluginApi("0.8.36", (api) => {
|
||||
api.modifyClass("route:admin-dashboard", {
|
||||
pluginId: "custom-wizard",
|
||||
|
||||
setupController(controller) {
|
||||
this._super(...arguments);
|
||||
|
||||
controller.loadCriticalNotices();
|
||||
controller.subscribe();
|
||||
},
|
||||
});
|
||||
|
||||
api.modifyClass("controller:admin-dashboard", {
|
||||
pluginId: "custom-wizard",
|
||||
criticalNotices: A(),
|
||||
|
||||
unsubscribe() {
|
||||
this.messageBus.unsubscribe("/custom-wizard/notices");
|
||||
},
|
||||
|
||||
subscribe() {
|
||||
this.unsubscribe();
|
||||
this.messageBus.subscribe("/custom-wizard/notices", (data) => {
|
||||
if (isPresent(data.active_notice_count)) {
|
||||
this.loadCriticalNotices();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
loadCriticalNotices() {
|
||||
CustomWizardNotice.list({
|
||||
type: ["connection_error", "warning"],
|
||||
archetype: "plugin_status",
|
||||
visible: true,
|
||||
}).then((result) => {
|
||||
if (result.notices && result.notices.length) {
|
||||
const criticalNotices = A(
|
||||
result.notices.map((n) => CustomWizardNotice.create(n))
|
||||
);
|
||||
this.set("customWizardCriticalNotices", criticalNotices);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
api.modifyClass("component:d-navigation", {
|
||||
pluginId: "custom-wizard",
|
||||
actions: {
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
import Mixin from "@ember/object/mixin";
|
||||
import { bind, scheduleOnce } from "@ember/runloop";
|
||||
import { cookAsync } from "discourse/lib/text";
|
||||
import { createPopper } from "@popperjs/core";
|
||||
|
||||
export default Mixin.create({
|
||||
showCookedMessage: false,
|
||||
|
||||
didReceiveAttrs() {
|
||||
const message = this.notice.message;
|
||||
cookAsync(message).then((cooked) => {
|
||||
this.set("cookedMessage", cooked);
|
||||
});
|
||||
},
|
||||
|
||||
createMessageModal() {
|
||||
let container = this.element.querySelector(".notice-message");
|
||||
let modal = this.element.querySelector(".cooked-notice-message");
|
||||
|
||||
this._popper = createPopper(container, modal, {
|
||||
strategy: "absolute",
|
||||
placement: "bottom-start",
|
||||
modifiers: [
|
||||
{
|
||||
name: "preventOverflow",
|
||||
},
|
||||
{
|
||||
name: "offset",
|
||||
options: {
|
||||
offset: [0, 5],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
$(document).on("click", bind(this, this.documentClick));
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
$(document).off("click", bind(this, this.documentClick));
|
||||
},
|
||||
|
||||
documentClick(event) {
|
||||
if (this._state === "destroying") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!event.target.closest(
|
||||
`[data-notice-id="${this.notice.id}"] .notice-message`
|
||||
)
|
||||
) {
|
||||
this.set("showCookedMessage", false);
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggleCookedMessage() {
|
||||
this.toggleProperty("showCookedMessage");
|
||||
|
||||
if (this.showCookedMessage) {
|
||||
scheduleOnce("afterRender", this, this.createMessageModal);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,74 +0,0 @@
|
|||
import EmberObject from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { and, not, notEmpty } from "@ember/object/computed";
|
||||
import { dasherize } from "@ember/string";
|
||||
import I18n from "I18n";
|
||||
|
||||
const CustomWizardNotice = EmberObject.extend({
|
||||
expired: notEmpty("expired_at"),
|
||||
dismissed: notEmpty("dismissed_at"),
|
||||
hidden: notEmpty("hidden_at"),
|
||||
notHidden: not("hidden"),
|
||||
notDismissed: not("dismissed"),
|
||||
canDismiss: and("dismissable", "notDismissed"),
|
||||
canHide: and("can_hide", "notHidden"),
|
||||
|
||||
@discourseComputed("type")
|
||||
typeClass(type) {
|
||||
return dasherize(type);
|
||||
},
|
||||
|
||||
@discourseComputed("type")
|
||||
typeLabel(type) {
|
||||
return I18n.t(`admin.wizard.notice.type.${type}`);
|
||||
},
|
||||
|
||||
dismiss() {
|
||||
if (!this.get("canDismiss")) {
|
||||
return;
|
||||
}
|
||||
|
||||
return ajax(`/admin/wizards/notice/${this.get("id")}/dismiss`, {
|
||||
type: "PUT",
|
||||
})
|
||||
.then((result) => {
|
||||
if (result.success) {
|
||||
this.set("dismissed_at", result.dismissed_at);
|
||||
}
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
hide() {
|
||||
if (!this.get("canHide")) {
|
||||
return;
|
||||
}
|
||||
|
||||
return ajax(`/admin/wizards/notice/${this.get("id")}/hide`, { type: "PUT" })
|
||||
.then((result) => {
|
||||
if (result.success) {
|
||||
this.set("hidden_at", result.hidden_at);
|
||||
}
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
});
|
||||
|
||||
CustomWizardNotice.reopenClass({
|
||||
list(data = {}) {
|
||||
return ajax("/admin/wizards/notice", {
|
||||
type: "GET",
|
||||
data,
|
||||
}).catch(popupAjaxError);
|
||||
},
|
||||
|
||||
dismissAll() {
|
||||
return ajax("/admin/wizards/notice/dismiss", {
|
||||
type: "PUT",
|
||||
}).catch(popupAjaxError);
|
||||
},
|
||||
});
|
||||
|
||||
export default CustomWizardNotice;
|
|
@ -1,33 +0,0 @@
|
|||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import EmberObject from "@ember/object";
|
||||
|
||||
const CustomWizardSubscription = EmberObject.extend();
|
||||
|
||||
const basePath = "/admin/wizards/subscription";
|
||||
|
||||
CustomWizardSubscription.reopenClass({
|
||||
status() {
|
||||
return ajax(basePath, {
|
||||
type: "GET",
|
||||
}).catch(popupAjaxError);
|
||||
},
|
||||
|
||||
authorize() {
|
||||
window.location.href = `${basePath}/authorize`;
|
||||
},
|
||||
|
||||
unauthorize() {
|
||||
return ajax(`${basePath}/authorize`, {
|
||||
type: "DELETE",
|
||||
}).catch(popupAjaxError);
|
||||
},
|
||||
|
||||
update() {
|
||||
return ajax(basePath, {
|
||||
type: "POST",
|
||||
}).catch(popupAjaxError);
|
||||
},
|
||||
});
|
||||
|
||||
export default CustomWizardSubscription;
|
|
@ -1,17 +0,0 @@
|
|||
import CustomWizardNotice from "../models/custom-wizard-notice";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { A } from "@ember/array";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
model() {
|
||||
return CustomWizardNotice.list({ include_all: true });
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
controller.setProperties({
|
||||
notices: A(
|
||||
model.notices.map((notice) => CustomWizardNotice.create(notice))
|
||||
),
|
||||
});
|
||||
},
|
||||
});
|
|
@ -1,19 +0,0 @@
|
|||
import CustomWizardSubscription from "../models/custom-wizard-subscription";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
model() {
|
||||
return CustomWizardSubscription.status();
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
controller.set("model", model);
|
||||
controller.setup();
|
||||
},
|
||||
|
||||
actions: {
|
||||
authorize() {
|
||||
CustomWizardSubscription.authorize();
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,49 +0,0 @@
|
|||
<div class="admin-wizard-controls">
|
||||
<h3>{{i18n "admin.wizard.notices.title"}}</h3>
|
||||
|
||||
<div class="buttons">
|
||||
{{d-button
|
||||
label="admin.wizard.notice.dismiss_all.label"
|
||||
title="admin.wizard.notice.dismiss_all.title"
|
||||
action=(action "dismissAll")
|
||||
disabled=allDismisssed
|
||||
icon="check"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{wizard-message
|
||||
key=messageKey
|
||||
url=messageUrl
|
||||
type=messageType
|
||||
opts=messageOpts
|
||||
items=messageItems
|
||||
loading=loading
|
||||
component="notices"}}
|
||||
|
||||
<div class="wizard-table">
|
||||
{{#load-more selector=".wizard-table tr" action=(action "loadMore")}}
|
||||
{{#if hasNotices}}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{I18n "admin.wizard.notice.time"}}</th>
|
||||
<th>{{I18n "admin.wizard.notice.type.label"}}</th>
|
||||
<th>{{I18n "admin.wizard.notice.title"}}</th>
|
||||
<th>{{I18n "admin.wizard.notice.status"}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each notices as |notice|}}
|
||||
{{wizard-notice-row notice=notice}}
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
{{#unless loadingMore}}
|
||||
<p>{{i18n "search.no_results"}}</p>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
|
||||
{{conditional-loading-spinner condition=loadingMore}}
|
||||
{{/load-more}}
|
||||
</div>
|
|
@ -1,35 +0,0 @@
|
|||
<div class="admin-wizard-controls">
|
||||
<h3>{{i18n "admin.wizard.subscription.title"}}</h3>
|
||||
|
||||
<div class="buttons">
|
||||
{{#if model.authentication.active}}
|
||||
{{conditional-loading-spinner size="small" condition=unauthorizing}}
|
||||
<a {{action "unauthorize"}} title={{i18n "admin.wizard.subscription.unauthorize"}} role="button">
|
||||
{{i18n "admin.wizard.subscription.unauthorize"}}
|
||||
</a>
|
||||
<label title={{i18n "admin.wizard.subscription.authorized"}}>
|
||||
{{i18n "admin.wizard.subscription.authorized"}}
|
||||
</label>
|
||||
{{else}}
|
||||
{{d-button
|
||||
icon="id-card"
|
||||
class="btn-primary"
|
||||
label="admin.wizard.subscription.authorize"
|
||||
title="admin.wizard.subscription.authorize"
|
||||
action=(route-action "authorize")}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{wizard-message
|
||||
key=messageKey
|
||||
url=messageUrl
|
||||
type=messageType
|
||||
opts=messageOpts
|
||||
component="subscription"}}
|
||||
|
||||
<div class="admin-wizard-container">
|
||||
{{#if showSubscription}}
|
||||
{{wizard-subscription subscription=model.subscription}}
|
||||
{{/if}}
|
||||
</div>
|
|
@ -7,15 +7,8 @@
|
|||
{{/if}}
|
||||
{{nav-item route="adminWizardsLogs" label="admin.wizard.log.nav_label"}}
|
||||
{{nav-item route="adminWizardsManager" label="admin.wizard.manager.nav_label"}}
|
||||
{{nav-item route="adminWizardsSubscription" label="admin.wizard.subscription.nav_label"}}
|
||||
|
||||
<div class="admin-actions">
|
||||
<div class="wizard-notices-link">
|
||||
{{nav-item tagName="div" route="adminWizardsNotices" label="admin.wizard.notices.nav_label"}}
|
||||
{{#if activeNoticeCount}}
|
||||
<span class="active-notice-count">{{activeNoticeCount}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<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>
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
<td class="small">
|
||||
{{#if notice.updated_at}}
|
||||
{{notice-badge class="notice-updated-at" date=notice.updated_at label="admin.wizard.notice.updated_at" leaveAgo=true}}
|
||||
{{else}}
|
||||
{{notice-badge class="notice-created-at" date=notice.created_at label="admin.wizard.notice.created_at" leaveAgo=true}}
|
||||
{{/if}}
|
||||
</td>
|
||||
<td>{{notice.typeLabel}}</td>
|
||||
<td class="notice-message">
|
||||
<a role="button" {{action "toggleCookedMessage"}} class="show-notice-message">{{notice.title}}</a>
|
||||
{{#if showCookedMessage}}
|
||||
<span class="cooked-notice-message">{{cookedMessage}}</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
<td>
|
||||
{{#if notice.canDismiss}}
|
||||
{{d-button
|
||||
action="dismiss"
|
||||
label="admin.wizard.notice.dismiss.label"
|
||||
title="admin.wizard.notice.dismiss.title"
|
||||
class="btn-dismiss"
|
||||
icon="check"}}
|
||||
{{else if notice.dismissed}}
|
||||
<span>{{i18n "admin.wizard.notice.dismissed_at"}} {{format-date notice.dismissed_at leaveAgo="true"}}</span>
|
||||
{{else if notice.expired}}
|
||||
<span>{{i18n "admin.wizard.notice.expired_at"}} {{format-date notice.expired_at leaveAgo="true"}}</span>
|
||||
{{else}}
|
||||
<span>{{i18n "admin.wizard.notice.active"}}</span>
|
||||
{{/if}}
|
||||
</td>
|
|
@ -1,39 +0,0 @@
|
|||
<div class="notice-header">
|
||||
<div class="notice-title notice-badge notice-message">
|
||||
<a role="button" {{action "toggleCookedMessage"}} class="show-notice-message">{{notice.title}}</a>
|
||||
{{#if showCookedMessage}}
|
||||
<span class="cooked-notice-message">{{cookedMessage}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="notice-header-right">
|
||||
{{#if notice.expired}}
|
||||
{{notice-badge class="notice-expired-at" icon="check" label="admin.wizard.notice.expired_at" date=notice.expired_at}}
|
||||
{{/if}}
|
||||
{{#if showPlugin}}
|
||||
{{notice-badge class="notice-plugin" icon="plug" title="admin.wizard.notice.plugin" label="admin.wizard.notice.plugin" url="/admin/wizards/notices"}}
|
||||
{{/if}}
|
||||
{{notice-badge class="notice-created-at" icon="far-clock" label="admin.wizard.notice.created_at" date=notice.created_at leaveAgo=true}}
|
||||
{{#if notice.updated_at}}
|
||||
{{notice-badge class="notice-updated-at" icon="far-clock" label="admin.wizard.notice.updated_at" date=notice.updated_at}}
|
||||
{{/if}}
|
||||
|
||||
{{#if notice.canDismiss}}
|
||||
<div class="dismiss-notice-container">
|
||||
{{#if dismissing}}
|
||||
{{loading-spinner size="small"}}
|
||||
{{else}}
|
||||
<a {{action "dismiss"}} role="button" class="dismiss-notice">{{d-icon "times"}}</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if notice.canHide}}
|
||||
<div class="hide-notice-container">
|
||||
{{#if hiding}}
|
||||
{{loading-spinner size="small"}}
|
||||
{{else}}
|
||||
<a {{action "hide"}} role="button" class="hide-notice">{{d-icon "far-eye-slash"}}</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
|
@ -1,31 +0,0 @@
|
|||
<div class="title-container">
|
||||
<h3 class="subscription-title">{{title}}</h3>
|
||||
|
||||
<div class="buttons">
|
||||
<span>
|
||||
{{#if updating}}
|
||||
{{loading-spinner size="small"}}
|
||||
{{else if updateIcon}}
|
||||
{{d-icon updateIcon}}
|
||||
{{/if}}
|
||||
</span>
|
||||
{{d-button
|
||||
icon="sync"
|
||||
action=(action "update")
|
||||
disabled=updating
|
||||
title="admin.wizard.subscription.subscription.update"
|
||||
label="admin.wizard.subscription.subscription.update"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if subscribed}}
|
||||
<div class="detail-container">
|
||||
<div class="subscription-state {{stateClass}}" title={{stateLabel}}>{{stateLabel}}</div>
|
||||
|
||||
{{#if subscription.updated_at}}
|
||||
<div class="subscription-updated-at" title={{subscription.updated_at}}>
|
||||
{{i18n "admin.wizard.subscription.subscription.last_updated"}} {{format-date subscription.updated_at leaveAgo="true"}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
|
@ -1,5 +1,6 @@
|
|||
// discourse-skip-module
|
||||
|
||||
if (window.location.pathname.indexOf("/w/") > -1 && Ember.testing) {
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
document.body.insertAdjacentHTML(
|
||||
"afterbegin",
|
||||
|
@ -15,3 +16,4 @@ Object.keys(requirejs.entries).forEach(function (entry) {
|
|||
requirejs(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -54,20 +54,6 @@ en:
|
|||
after_time: "After time setting is invalid."
|
||||
liquid_syntax_error: "Liquid syntax error in %{attribute}: %{message}"
|
||||
|
||||
notice:
|
||||
connection_error: "Failed to connect to http://%{domain}"
|
||||
compatibility_issue:
|
||||
title: The Custom Wizard Plugin is incompatibile with the latest version of Discourse.
|
||||
message: Please check the Custom Wizard Plugin status on [%{domain}](http://%{domain}) before updating Discourse.
|
||||
plugin_status:
|
||||
connection_error:
|
||||
title: Unable to connect to the Custom Wizard Plugin status server
|
||||
message: Please check the Custom Wizard Plugin status on [%{domain}](http://%{domain}) before updating Discourse. If this issue persists contact <a href="mailto:support@thepavilion.io">support@thepavilion.io</a> for further assistance.
|
||||
subscription_message:
|
||||
connection_error:
|
||||
title: Unable to connect to the Custom Wizard Plugin subscription server
|
||||
message: If this issue persists contact <a href="mailto:support@thepavilion.io">support@thepavilion.io</a> for further assistance.
|
||||
|
||||
site_settings:
|
||||
custom_wizard_enabled: "Enable custom wizards."
|
||||
wizard_redirect_exclude_paths: "Routes excluded from wizard redirects."
|
||||
|
|
|
@ -45,17 +45,5 @@ Discourse::Application.routes.append do
|
|||
get 'admin/wizards/manager/export' => 'admin_manager#export'
|
||||
post 'admin/wizards/manager/import' => 'admin_manager#import'
|
||||
delete 'admin/wizards/manager/destroy' => 'admin_manager#destroy'
|
||||
|
||||
get 'admin/wizards/subscription' => 'admin_subscription#index'
|
||||
post 'admin/wizards/subscription' => 'admin_subscription#update_subscription'
|
||||
get 'admin/wizards/subscription/authorize' => 'admin_subscription#authorize'
|
||||
get 'admin/wizards/subscription/authorize/callback' => 'admin_subscription#authorize_callback'
|
||||
delete 'admin/wizards/subscription/authorize' => 'admin_subscription#destroy_authentication'
|
||||
|
||||
get 'admin/wizards/notice' => 'admin_notice#index'
|
||||
put 'admin/wizards/notice/:notice_id/dismiss' => 'admin_notice#dismiss'
|
||||
put 'admin/wizards/notice/:notice_id/hide' => 'admin_notice#hide'
|
||||
put 'admin/wizards/notice/dismiss' => 'admin_notice#dismiss_all'
|
||||
get 'admin/wizards/notices' => 'admin_notice#index'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,358 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CustomWizard::Notice
|
||||
include ActiveModel::Serialization
|
||||
|
||||
PLUGIN_STATUS_DOMAINS = {
|
||||
"main" => "plugins.discourse.pavilion.tech",
|
||||
"master" => "plugins.discourse.pavilion.tech",
|
||||
"tests-passed" => "plugins.discourse.pavilion.tech",
|
||||
"stable" => "stable.plugins.discourse.pavilion.tech"
|
||||
}
|
||||
SUBSCRIPTION_MESSAGE_DOMAIN = "test.thepavilion.io"
|
||||
LOCALHOST_DOMAIN = "localhost:3000"
|
||||
PLUGIN_STATUSES_TO_WARN = %w(incompatible tests_failing)
|
||||
CHECK_PLUGIN_STATUS_ON_BRANCH = %w(tests-passed main stable)
|
||||
PAGE_LIMIT = 30
|
||||
|
||||
attr_reader :id,
|
||||
:title,
|
||||
:message,
|
||||
:type,
|
||||
:archetype,
|
||||
:created_at
|
||||
|
||||
attr_accessor :retrieved_at,
|
||||
:updated_at,
|
||||
:dismissed_at,
|
||||
:expired_at,
|
||||
:hidden_at
|
||||
|
||||
def initialize(attrs)
|
||||
@id = self.class.generate_notice_id(attrs[:title], attrs[:created_at])
|
||||
@title = attrs[:title]
|
||||
@message = attrs[:message]
|
||||
@type = attrs[:type].to_i
|
||||
@archetype = attrs[:archetype].to_i
|
||||
@created_at = attrs[:created_at]
|
||||
@updated_at = attrs[:updated_at]
|
||||
@retrieved_at = attrs[:retrieved_at]
|
||||
@dismissed_at = attrs[:dismissed_at]
|
||||
@expired_at = attrs[:expired_at]
|
||||
@hidden_at = attrs[:hidden_at]
|
||||
end
|
||||
|
||||
def dismiss!
|
||||
if dismissable?
|
||||
self.dismissed_at = DateTime.now.iso8601(3)
|
||||
self.save_and_publish
|
||||
end
|
||||
end
|
||||
|
||||
def hide!
|
||||
if can_hide?
|
||||
self.hidden_at = DateTime.now.iso8601(3)
|
||||
self.save_and_publish
|
||||
end
|
||||
end
|
||||
|
||||
def expire!
|
||||
if !expired?
|
||||
self.expired_at = DateTime.now.iso8601(3)
|
||||
self.save_and_publish
|
||||
end
|
||||
end
|
||||
|
||||
def save_and_publish
|
||||
if self.save
|
||||
self.class.publish_notice_count
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def expired?
|
||||
expired_at.present?
|
||||
end
|
||||
|
||||
def dismissed?
|
||||
dismissed_at.present?
|
||||
end
|
||||
|
||||
def dismissable?
|
||||
!expired? && !dismissed? && type === self.class.types[:info]
|
||||
end
|
||||
|
||||
def hidden?
|
||||
hidden_at.present?
|
||||
end
|
||||
|
||||
def can_hide?
|
||||
!hidden? && (
|
||||
type === self.class.types[:connection_error] ||
|
||||
type === self.class.types[:warning]
|
||||
) && (
|
||||
archetype === self.class.archetypes[:plugin_status]
|
||||
)
|
||||
end
|
||||
|
||||
def save
|
||||
attrs = {
|
||||
expired_at: expired_at,
|
||||
updated_at: updated_at,
|
||||
retrieved_at: retrieved_at,
|
||||
created_at: created_at,
|
||||
title: title,
|
||||
message: message,
|
||||
type: type,
|
||||
archetype: archetype
|
||||
}
|
||||
|
||||
if current = self.class.find(self.id)
|
||||
attrs[:dismissed_at] = current.dismissed_at || self.dismissed_at
|
||||
attrs[:hidden_at] = current.hidden_at || self.hidden_at
|
||||
end
|
||||
|
||||
self.class.store(id, attrs)
|
||||
end
|
||||
|
||||
def self.types
|
||||
@types ||= Enum.new(
|
||||
info: 0,
|
||||
warning: 1,
|
||||
connection_error: 2
|
||||
)
|
||||
end
|
||||
|
||||
def self.archetypes
|
||||
@archetypes ||= Enum.new(
|
||||
subscription_message: 0,
|
||||
plugin_status: 1
|
||||
)
|
||||
end
|
||||
|
||||
def self.update(skip_subscription: false, skip_plugin: false)
|
||||
notices = []
|
||||
|
||||
if !skip_subscription
|
||||
subscription_messages = request(:subscription_message)
|
||||
|
||||
if subscription_messages.present?
|
||||
subscription_notices = convert_subscription_messages_to_notices(subscription_messages[:messages])
|
||||
notices.push(*subscription_notices)
|
||||
end
|
||||
end
|
||||
|
||||
if !skip_plugin && request_plugin_status?
|
||||
plugin_status = request(:plugin_status)
|
||||
|
||||
if plugin_status.present? && plugin_status[:status].present?
|
||||
plugin_notice = convert_plugin_status_to_notice(plugin_status)
|
||||
notices.push(plugin_notice) if plugin_notice
|
||||
end
|
||||
end
|
||||
|
||||
if notices.any?
|
||||
notices.each do |notice_data|
|
||||
notice = new(notice_data)
|
||||
notice.retrieved_at = DateTime.now.iso8601(3)
|
||||
notice.save
|
||||
end
|
||||
end
|
||||
|
||||
publish_notice_count
|
||||
end
|
||||
|
||||
def self.publish_notice_count
|
||||
payload = {
|
||||
active_notice_count: CustomWizard::Notice.active_count
|
||||
}
|
||||
MessageBus.publish("/custom-wizard/notices", payload, group_ids: [Group::AUTO_GROUPS[:admins]])
|
||||
end
|
||||
|
||||
def self.convert_subscription_messages_to_notices(messages)
|
||||
messages.reduce([]) do |result, message|
|
||||
id = generate_notice_id(message[:title], message[:created_at])
|
||||
result.push(
|
||||
id: id,
|
||||
title: message[:title],
|
||||
message: message[:message],
|
||||
type: types[message[:type].to_sym],
|
||||
archetype: archetypes[:subscription_message],
|
||||
created_at: message[:created_at],
|
||||
expired_at: message[:expired_at]
|
||||
)
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
def self.convert_plugin_status_to_notice(plugin_status)
|
||||
notice = nil
|
||||
|
||||
if PLUGIN_STATUSES_TO_WARN.include?(plugin_status[:status])
|
||||
title = I18n.t('wizard.notice.compatibility_issue.title')
|
||||
created_at = plugin_status[:status_changed_at]
|
||||
id = generate_notice_id(title, created_at)
|
||||
|
||||
unless exists?(id)
|
||||
message = I18n.t('wizard.notice.compatibility_issue.message', domain: plugin_status_domain)
|
||||
notice = {
|
||||
id: id,
|
||||
title: title,
|
||||
message: message,
|
||||
type: types[:warning],
|
||||
archetype: archetypes[:plugin_status],
|
||||
created_at: created_at
|
||||
}
|
||||
end
|
||||
else
|
||||
expire_all(types[:warning], archetypes[:plugin_status])
|
||||
end
|
||||
|
||||
notice
|
||||
end
|
||||
|
||||
def self.notify_connection_errors(archetype)
|
||||
domain = self.send("#{archetype.to_s}_domain")
|
||||
title = I18n.t("wizard.notice.#{archetype.to_s}.connection_error.title")
|
||||
notices = list(type: types[:connection_error], archetype: archetypes[archetype.to_sym], title: title)
|
||||
|
||||
if notices.any?
|
||||
notice = notices.first
|
||||
notice.updated_at = DateTime.now.iso8601(3)
|
||||
notice.save
|
||||
else
|
||||
notice = new(
|
||||
title: title,
|
||||
message: I18n.t("wizard.notice.#{archetype.to_s}.connection_error.message", domain: domain),
|
||||
archetype: archetypes[archetype.to_sym],
|
||||
type: types[:connection_error],
|
||||
created_at: DateTime.now.iso8601(3),
|
||||
updated_at: DateTime.now.iso8601(3)
|
||||
)
|
||||
notice.save
|
||||
end
|
||||
end
|
||||
|
||||
def self.request_plugin_status?
|
||||
CHECK_PLUGIN_STATUS_ON_BRANCH.include?(Discourse.git_branch) || Rails.env.test? || Rails.env.development?
|
||||
end
|
||||
|
||||
def self.subscription_message_domain
|
||||
return LOCALHOST_DOMAIN if (Rails.env.test? || Rails.env.development?)
|
||||
SUBSCRIPTION_MESSAGE_DOMAIN
|
||||
end
|
||||
|
||||
def self.subscription_message_url
|
||||
"https://#{subscription_message_domain}/subscription-server/messages.json"
|
||||
end
|
||||
|
||||
def self.plugin_status_domain
|
||||
return LOCALHOST_DOMAIN if (Rails.env.test? || Rails.env.development?)
|
||||
PLUGIN_STATUS_DOMAINS[Discourse.git_branch]
|
||||
end
|
||||
|
||||
def self.plugin_status_url
|
||||
"https://#{plugin_status_domain}/plugin-manager/status/discourse-custom-wizard"
|
||||
end
|
||||
|
||||
def self.request(archetype)
|
||||
url = self.send("#{archetype.to_s}_url")
|
||||
|
||||
begin
|
||||
response = Excon.get(url)
|
||||
rescue Excon::Error::Socket, Excon::Error::Timeout => e
|
||||
response = nil
|
||||
end
|
||||
connection_error = CustomWizard::Notice::ConnectionError.new(archetype)
|
||||
|
||||
if response && response.status == 200
|
||||
connection_error.expire!
|
||||
expire_all(types[:connection_error], archetypes[archetype.to_sym])
|
||||
|
||||
begin
|
||||
data = JSON.parse(response.body).deep_symbolize_keys
|
||||
rescue JSON::ParserError
|
||||
return nil
|
||||
end
|
||||
|
||||
data
|
||||
else
|
||||
connection_error.create!
|
||||
notify_connection_errors(archetype) if connection_error.reached_limit?
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def self.namespace
|
||||
"#{CustomWizard::PLUGIN_NAME}_notice"
|
||||
end
|
||||
|
||||
def self.find(id)
|
||||
raw = PluginStore.get(namespace, id)
|
||||
new(raw.symbolize_keys) if raw.present?
|
||||
end
|
||||
|
||||
def self.exists?(id)
|
||||
PluginStoreRow.where(plugin_name: namespace, key: id).exists?
|
||||
end
|
||||
|
||||
def self.store(id, raw_notice)
|
||||
PluginStore.set(namespace, id, raw_notice)
|
||||
end
|
||||
|
||||
def self.list_query(type: nil, archetype: nil, title: nil, include_all: false, page: nil, visible: false)
|
||||
query = PluginStoreRow.where(plugin_name: namespace)
|
||||
query = query.where("(value::json->>'hidden_at') IS NULL") if visible
|
||||
query = query.where("(value::json->>'dismissed_at') IS NULL") unless include_all
|
||||
query = query.where("(value::json->>'expired_at') IS NULL") unless include_all
|
||||
query = query.where("(value::json->>'archetype')::integer = ?", archetype) if archetype
|
||||
if type
|
||||
type_query_str = type.is_a?(Array) ? "(value::json->>'type')::integer IN (?)" : "(value::json->>'type')::integer = ?"
|
||||
query = query.where(type_query_str, type)
|
||||
end
|
||||
query = query.where("(value::json->>'title')::text = ?", title) if title
|
||||
query = query.limit(PAGE_LIMIT).offset(page.to_i * PAGE_LIMIT) if !page.nil?
|
||||
query.order("value::json->>'expired_at' DESC, value::json->>'updated_at' DESC,value::json->>'dismissed_at' DESC, value::json->>'created_at' DESC")
|
||||
end
|
||||
|
||||
def self.list(type: nil, archetype: nil, title: nil, include_all: false, page: 0, visible: false)
|
||||
list_query(type: type, archetype: archetype, title: title, include_all: include_all, page: page, visible: visible)
|
||||
.map { |r| self.new(JSON.parse(r.value).symbolize_keys) }
|
||||
end
|
||||
|
||||
def self.active_count
|
||||
list_query.count
|
||||
end
|
||||
|
||||
def self.dismiss_all
|
||||
dismissed_count = PluginStoreRow.where("
|
||||
plugin_name = '#{namespace}' AND
|
||||
(value::json->>'type')::integer = #{types[:info]} AND
|
||||
(value::json->>'expired_at') IS NULL AND
|
||||
(value::json->>'dismissed_at') IS NULL
|
||||
").update_all("
|
||||
value = jsonb_set(value::jsonb, '{dismissed_at}', (to_json(now())::text)::jsonb, true)
|
||||
")
|
||||
publish_notice_count if dismissed_count.to_i > 0
|
||||
dismissed_count
|
||||
end
|
||||
|
||||
def self.expire_all(type, archetype)
|
||||
expired_count = PluginStoreRow.where("
|
||||
plugin_name = '#{namespace}' AND
|
||||
(value::json->>'type')::integer = #{type} AND
|
||||
(value::json->>'archetype')::integer = #{archetype} AND
|
||||
(value::json->>'expired_at') IS NULL
|
||||
").update_all("
|
||||
value = jsonb_set(value::jsonb, '{expired_at}', (to_json(now())::text)::jsonb, true)
|
||||
")
|
||||
publish_notice_count if expired_count.to_i > 0
|
||||
expired_count
|
||||
end
|
||||
|
||||
def self.generate_notice_id(title, created_at)
|
||||
Digest::SHA1.hexdigest("#{title}-#{created_at}")
|
||||
end
|
||||
end
|
|
@ -1,77 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CustomWizard::Notice::ConnectionError
|
||||
|
||||
attr_reader :archetype
|
||||
|
||||
def initialize(archetype)
|
||||
@archetype = archetype
|
||||
end
|
||||
|
||||
def create!
|
||||
if attrs = current_error
|
||||
key = "#{archetype.to_s}_error_#{attrs[:id]}"
|
||||
attrs[:updated_at] = Time.now
|
||||
attrs[:count] = attrs[:count].to_i + 1
|
||||
else
|
||||
domain = CustomWizard::Notice.send("#{archetype.to_s}_domain")
|
||||
id = SecureRandom.hex(8)
|
||||
attrs = {
|
||||
id: id,
|
||||
message: I18n.t("wizard.notice.connection_error", domain: domain),
|
||||
archetype: CustomWizard::Notice.archetypes[archetype.to_sym],
|
||||
created_at: Time.now,
|
||||
count: 1
|
||||
}
|
||||
key = "#{archetype.to_s}_error_#{id}"
|
||||
end
|
||||
|
||||
PluginStore.set(namespace, key, attrs)
|
||||
|
||||
@current_error = nil
|
||||
end
|
||||
|
||||
def expire!
|
||||
if query = current_error(query_only: true)
|
||||
record = query.first
|
||||
error = JSON.parse(record.value)
|
||||
error['expired_at'] = Time.now
|
||||
record.value = error.to_json
|
||||
record.save
|
||||
end
|
||||
end
|
||||
|
||||
def plugin_status_limit
|
||||
5
|
||||
end
|
||||
|
||||
def subscription_message_limit
|
||||
10
|
||||
end
|
||||
|
||||
def limit
|
||||
self.send("#{archetype.to_s}_limit")
|
||||
end
|
||||
|
||||
def reached_limit?
|
||||
return false unless current_error.present?
|
||||
current_error[:count].to_i >= limit
|
||||
end
|
||||
|
||||
def namespace
|
||||
"#{CustomWizard::PLUGIN_NAME}_notice_connection"
|
||||
end
|
||||
|
||||
def current_error(query_only: false)
|
||||
@current_error ||= begin
|
||||
query = PluginStoreRow.where(plugin_name: namespace)
|
||||
query = query.where("(value::json->>'archetype')::integer = ?", CustomWizard::Notice.archetypes[archetype.to_sym])
|
||||
query = query.where("(value::json->>'expired_at') IS NULL")
|
||||
|
||||
return nil if !query.exists?
|
||||
return query if query_only
|
||||
|
||||
JSON.parse(query.first.value).deep_symbolize_keys
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,240 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CustomWizard::Subscription
|
||||
include ActiveModel::Serialization
|
||||
|
||||
attr_accessor :authentication,
|
||||
:subscription
|
||||
|
||||
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: [],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
def initialize
|
||||
@authentication = CustomWizard::Subscription::Authentication.new(get_authentication)
|
||||
@subscription = CustomWizard::Subscription::Subscription.new(get_subscription)
|
||||
end
|
||||
|
||||
def authorized?
|
||||
@authentication.active?
|
||||
end
|
||||
|
||||
def subscribed?
|
||||
@subscription.active?
|
||||
end
|
||||
|
||||
def server
|
||||
"test.thepavilion.io"
|
||||
end
|
||||
|
||||
def subscription_type
|
||||
"stripe"
|
||||
end
|
||||
|
||||
def type
|
||||
@subscription.type
|
||||
end
|
||||
|
||||
def client_name
|
||||
"custom-wizard"
|
||||
end
|
||||
|
||||
def scope
|
||||
"discourse-subscription-server:user_subscription"
|
||||
end
|
||||
|
||||
def requires_additional_subscription(kategory, sub_kategory)
|
||||
case kategory
|
||||
when "actions"
|
||||
case self.type
|
||||
when "business"
|
||||
[]
|
||||
when "standard"
|
||||
SUBSCRIPTION_LEVELS[:business][kategory.to_sym]
|
||||
else
|
||||
SUBSCRIPTION_LEVELS[:standard][kategory.to_sym] + SUBSCRIPTION_LEVELS[:business][kategory.to_sym]
|
||||
end
|
||||
when "custom_fields"
|
||||
case self.type
|
||||
when "business"
|
||||
[]
|
||||
when "standard"
|
||||
SUBSCRIPTION_LEVELS[:business][kategory.to_sym][sub_kategory.to_sym]
|
||||
else
|
||||
SUBSCRIPTION_LEVELS[:standard][kategory.to_sym][sub_kategory.to_sym] + SUBSCRIPTION_LEVELS[:business][kategory.to_sym][sub_kategory.to_sym]
|
||||
end
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if @authentication.active?
|
||||
response = Excon.get(
|
||||
"https://#{server}/subscription-server/user-subscriptions/#{subscription_type}/#{client_name}",
|
||||
headers: {
|
||||
"User-Api-Key" => @authentication.api_key
|
||||
}
|
||||
)
|
||||
|
||||
if response.status == 200
|
||||
begin
|
||||
data = JSON.parse(response.body).deep_symbolize_keys
|
||||
rescue JSON::ParserError
|
||||
return false
|
||||
end
|
||||
|
||||
return false unless data && data.is_a?(Hash)
|
||||
subscriptions = data[:subscriptions]
|
||||
|
||||
if subscriptions.present? && type = subscriptions.first[:price_nickname]
|
||||
@subscription = set_subscription(type)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
destroy_subscription
|
||||
false
|
||||
end
|
||||
|
||||
def destroy_subscription
|
||||
if remove_subscription
|
||||
@subscription = CustomWizard::Subscription::Subscription.new(get_subscription)
|
||||
!@subscription.active?
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def authentication_url(user_id, request_id)
|
||||
keys = @authentication.generate_keys(user_id, request_id)
|
||||
params = {
|
||||
public_key: keys.public_key,
|
||||
nonce: keys.nonce,
|
||||
client_id: @authentication.client_id,
|
||||
auth_redirect: "#{Discourse.base_url}/admin/wizards/subscription/authorize/callback",
|
||||
application_name: SiteSetting.title,
|
||||
scopes: scope
|
||||
}
|
||||
|
||||
uri = URI.parse("https://#{server}/user-api-key/new")
|
||||
uri.query = URI.encode_www_form(params)
|
||||
uri.to_s
|
||||
end
|
||||
|
||||
def authentication_response(request_id, payload)
|
||||
data = @authentication.decrypt_payload(request_id, payload)
|
||||
return false unless data.is_a?(Hash) && data[:key] && data[:user_id]
|
||||
|
||||
api_key = data[:key]
|
||||
user_id = data[:user_id]
|
||||
user = User.find(user_id)
|
||||
|
||||
if user&.admin
|
||||
@authentication = set_authentication(api_key, user.id)
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def destroy_authentication
|
||||
if remove_authentication
|
||||
@authentication = CustomWizard::Subscription::Authentication.new(get_authentication)
|
||||
!@authentication.active?
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def self.subscribed?
|
||||
self.new.subscribed?
|
||||
end
|
||||
|
||||
def self.type
|
||||
self.new.type
|
||||
end
|
||||
|
||||
def self.requires_additional_subscription(kategory, sub_kategory)
|
||||
self.new.requires_additional_subscription(kategory, sub_kategory)
|
||||
end
|
||||
|
||||
def self.authorized?
|
||||
self.new.authorized?
|
||||
end
|
||||
|
||||
def self.update
|
||||
self.new.update
|
||||
end
|
||||
|
||||
def self.namespace
|
||||
"custom_wizard_subscription"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def subscription_db_key
|
||||
"subscription"
|
||||
end
|
||||
|
||||
def authentication_db_key
|
||||
"authentication"
|
||||
end
|
||||
|
||||
def get_subscription
|
||||
raw = PluginStore.get(self.class.namespace, subscription_db_key)
|
||||
|
||||
if raw.present?
|
||||
OpenStruct.new(
|
||||
type: raw['type'],
|
||||
updated_at: raw['updated_at']
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def remove_subscription
|
||||
PluginStore.remove(self.class.namespace, subscription_db_key)
|
||||
end
|
||||
|
||||
def set_subscription(type)
|
||||
PluginStore.set(CustomWizard::Subscription.namespace, subscription_db_key, type: type, updated_at: Time.now)
|
||||
CustomWizard::Subscription::Subscription.new(get_subscription)
|
||||
end
|
||||
|
||||
def get_authentication
|
||||
raw = PluginStore.get(self.class.namespace, authentication_db_key)
|
||||
OpenStruct.new(
|
||||
key: raw && raw['key'],
|
||||
auth_by: raw && raw['auth_by'],
|
||||
auth_at: raw && raw['auth_at']
|
||||
)
|
||||
end
|
||||
|
||||
def set_authentication(key, user_id)
|
||||
PluginStore.set(self.class.namespace, authentication_db_key,
|
||||
key: key,
|
||||
auth_by: user_id,
|
||||
auth_at: Time.now
|
||||
)
|
||||
CustomWizard::Subscription::Authentication.new(get_authentication)
|
||||
end
|
||||
|
||||
def remove_authentication
|
||||
PluginStore.remove(self.class.namespace, authentication_db_key)
|
||||
get_authentication
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
class CustomWizard::Subscription::Authentication
|
||||
include ActiveModel::Serialization
|
||||
|
||||
attr_reader :client_id,
|
||||
:auth_by,
|
||||
:auth_at,
|
||||
:api_key
|
||||
|
||||
def initialize(auth)
|
||||
if auth
|
||||
@api_key = auth.key
|
||||
@auth_at = auth.auth_at
|
||||
@auth_by = auth.auth_by
|
||||
end
|
||||
|
||||
@client_id = get_client_id || set_client_id
|
||||
end
|
||||
|
||||
def active?
|
||||
@api_key.present?
|
||||
end
|
||||
|
||||
def generate_keys(user_id, request_id)
|
||||
rsa = OpenSSL::PKey::RSA.generate(2048)
|
||||
nonce = SecureRandom.hex(32)
|
||||
set_keys(request_id, user_id, rsa, nonce)
|
||||
|
||||
OpenStruct.new(nonce: nonce, public_key: rsa.public_key)
|
||||
end
|
||||
|
||||
def decrypt_payload(request_id, payload)
|
||||
keys = get_keys(request_id)
|
||||
|
||||
return false unless keys.present? && keys.pem
|
||||
delete_keys(request_id)
|
||||
|
||||
rsa = OpenSSL::PKey::RSA.new(keys.pem)
|
||||
decrypted_payload = rsa.private_decrypt(Base64.decode64(payload))
|
||||
|
||||
return false unless decrypted_payload.present?
|
||||
|
||||
begin
|
||||
data = JSON.parse(decrypted_payload).symbolize_keys
|
||||
rescue JSON::ParserError
|
||||
return false
|
||||
end
|
||||
|
||||
return false unless data[:nonce] == keys.nonce
|
||||
data[:user_id] = keys.user_id
|
||||
|
||||
data
|
||||
end
|
||||
|
||||
def get_keys(request_id)
|
||||
raw = PluginStore.get(CustomWizard::Subscription.namespace, "#{keys_db_key}_#{request_id}")
|
||||
OpenStruct.new(
|
||||
user_id: raw && raw['user_id'],
|
||||
pem: raw && raw['pem'],
|
||||
nonce: raw && raw['nonce']
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def keys_db_key
|
||||
"keys"
|
||||
end
|
||||
|
||||
def client_id_db_key
|
||||
"client_id"
|
||||
end
|
||||
|
||||
def set_keys(request_id, user_id, rsa, nonce)
|
||||
PluginStore.set(CustomWizard::Subscription.namespace, "#{keys_db_key}_#{request_id}",
|
||||
user_id: user_id,
|
||||
pem: rsa.export,
|
||||
nonce: nonce
|
||||
)
|
||||
end
|
||||
|
||||
def delete_keys(request_id)
|
||||
PluginStore.remove(CustomWizard::Subscription.namespace, "#{keys_db_key}_#{request_id}")
|
||||
end
|
||||
|
||||
def get_client_id
|
||||
PluginStore.get(CustomWizard::Subscription.namespace, client_id_db_key)
|
||||
end
|
||||
|
||||
def set_client_id
|
||||
client_id = SecureRandom.hex(32)
|
||||
PluginStore.set(CustomWizard::Subscription.namespace, client_id_db_key, client_id)
|
||||
client_id
|
||||
end
|
||||
end
|
|
@ -1,22 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
class CustomWizard::Subscription::Subscription
|
||||
include ActiveModel::Serialization
|
||||
|
||||
attr_reader :type,
|
||||
:updated_at
|
||||
|
||||
def initialize(subscription)
|
||||
if subscription
|
||||
@type = subscription.type
|
||||
@updated_at = subscription.updated_at
|
||||
end
|
||||
end
|
||||
|
||||
def types
|
||||
%w(none standard business)
|
||||
end
|
||||
|
||||
def active?
|
||||
types.include?(type) && updated_at.to_datetime > (Time.zone.now - 2.hours).to_datetime
|
||||
end
|
||||
end
|
21
plugin.rb
21
plugin.rb
|
@ -70,15 +70,11 @@ after_initialize do
|
|||
../app/controllers/custom_wizard/admin/logs.rb
|
||||
../app/controllers/custom_wizard/admin/manager.rb
|
||||
../app/controllers/custom_wizard/admin/custom_fields.rb
|
||||
../app/controllers/custom_wizard/admin/subscription.rb
|
||||
../app/controllers/custom_wizard/admin/notice.rb
|
||||
../app/controllers/custom_wizard/wizard.rb
|
||||
../app/controllers/custom_wizard/steps.rb
|
||||
../app/controllers/custom_wizard/realtime_validations.rb
|
||||
../app/jobs/regular/refresh_api_access_token.rb
|
||||
../app/jobs/regular/set_after_time_wizard.rb
|
||||
../app/jobs/scheduled/custom_wizard/update_subscription.rb
|
||||
../app/jobs/scheduled/custom_wizard/update_notices.rb
|
||||
../lib/custom_wizard/validators/template.rb
|
||||
../lib/custom_wizard/validators/update.rb
|
||||
../lib/custom_wizard/action_result.rb
|
||||
|
@ -97,11 +93,6 @@ after_initialize do
|
|||
../lib/custom_wizard/submission.rb
|
||||
../lib/custom_wizard/template.rb
|
||||
../lib/custom_wizard/wizard.rb
|
||||
../lib/custom_wizard/notice.rb
|
||||
../lib/custom_wizard/notice/connection_error.rb
|
||||
../lib/custom_wizard/subscription.rb
|
||||
../lib/custom_wizard/subscription/subscription.rb
|
||||
../lib/custom_wizard/subscription/authentication.rb
|
||||
../lib/custom_wizard/api/api.rb
|
||||
../lib/custom_wizard/api/authorization.rb
|
||||
../lib/custom_wizard/api/endpoint.rb
|
||||
|
@ -122,10 +113,6 @@ after_initialize do
|
|||
../app/serializers/custom_wizard/log_serializer.rb
|
||||
../app/serializers/custom_wizard/submission_serializer.rb
|
||||
../app/serializers/custom_wizard/realtime_validation/similar_topics_serializer.rb
|
||||
../app/serializers/custom_wizard/subscription/authentication_serializer.rb
|
||||
../app/serializers/custom_wizard/subscription/subscription_serializer.rb
|
||||
../app/serializers/custom_wizard/subscription_serializer.rb
|
||||
../app/serializers/custom_wizard/notice_serializer.rb
|
||||
../lib/custom_wizard/extensions/extra_locales_controller.rb
|
||||
../lib/custom_wizard/extensions/invites_controller.rb
|
||||
../lib/custom_wizard/extensions/users_controller.rb
|
||||
|
@ -271,14 +258,6 @@ after_initialize do
|
|||
"#{serializer_klass}_serializer".classify.constantize.prepend CustomWizardCustomFieldSerializer
|
||||
end
|
||||
|
||||
AdminDashboardData.add_problem_check do
|
||||
warning_notices = CustomWizard::Notice.list(
|
||||
type: CustomWizard::Notice.types[:warning],
|
||||
archetype: CustomWizard::Notice.archetypes[:plugin_status]
|
||||
)
|
||||
warning_notices.any? ? ActionView::Base.full_sanitizer.sanitize(warning_notices.first.message, tags: %w(a)) : nil
|
||||
end
|
||||
|
||||
reloadable_patch do |plugin|
|
||||
::TagsController.prepend CustomWizardTagsController
|
||||
::DiscourseTagging.singleton_class.prepend CustomWizardDiscourseTagging
|
||||
|
|
Laden …
In neuem Issue referenzieren