0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-11-22 09:20:29 +01:00

Remove subs and notices files

Dieser Commit ist enthalten in:
Angus McLeod 2022-03-16 15:49:25 +01:00
Ursprung c0b93fc166
Commit 5edfb4c41e
40 geänderte Dateien mit 17 neuen und 1826 gelöschten Zeilen

Datei anzeigen

@ -4,16 +4,7 @@ class CustomWizard::AdminController < ::Admin::AdminController
def index def index
render_json_dump( render_json_dump(
#TODO replace with appropriate static? api_section: ["business"].include?(CustomWizard::Subscription.type)
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
)
) )
end end

Datei anzeigen

@ -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

Datei anzeigen

@ -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

Datei anzeigen

@ -11,7 +11,6 @@ class CustomWizard::WizardController < ::ActionController::Base
before_action :preload_wizard_json before_action :preload_wizard_json
before_action :ensure_plugin_enabled before_action :ensure_plugin_enabled
before_action :update_subscription, only: [:index]
before_action :ensure_logged_in, only: [:skip] before_action :ensure_logged_in, only: [:skip]
helper_method :wizard_page_title helper_method :wizard_page_title
@ -123,8 +122,4 @@ class CustomWizard::WizardController < ::ActionController::Base
redirect_to path("/") redirect_to path("/")
end end
end end
def update_subscription
CustomWizard::Subscription.update
end
end end

Datei anzeigen

@ -1,9 +0,0 @@
# frozen_string_literal: true
class Jobs::CustomWizardUpdateNotices < ::Jobs::Scheduled
every 5.minutes
def execute(args = {})
CustomWizard::Notice.update
end
end

Datei anzeigen

@ -1,9 +0,0 @@
# frozen_string_literal: true
class Jobs::CustomWizardUpdateSubscription < ::Jobs::Scheduled
every 1.hour
def execute(args = {})
CustomWizard::Subscription.update
end
end

Datei anzeigen

@ -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

Datei anzeigen

@ -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

Datei anzeigen

@ -1,10 +0,0 @@
# frozen_string_literal: true
class CustomWizard::Subscription::SubscriptionSerializer < ApplicationSerializer
attributes :type,
:active,
:updated_at
def active
object.active?
end
end

Datei anzeigen

@ -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

Datei anzeigen

@ -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`;
},
});

Datei anzeigen

@ -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();
},
},
});

Datei anzeigen

@ -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);
});
},
},
});

Datei anzeigen

@ -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);
});
},
},
});

Datei anzeigen

@ -1,5 +0,0 @@
{{#if notices}}
{{#each notices as |notice|}}
{{wizard-notice notice=notice showPlugin=true}}
{{/each}}
{{/if}}

Datei anzeigen

@ -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"));
});
},
};

Datei anzeigen

@ -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)
);
}
}
);
},
},
});

Datei anzeigen

@ -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);
});
},
},
});

Datei anzeigen

@ -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 += "&nbsp;";
}
html += `<span>${I18n.t(attrs.label)}</span>`;
}
if (attrs.date) {
if (attrs.icon || attrs.label) {
html += "&nbsp;";
}
let dateAttrs = {};
if (attrs.leaveAgo) {
dateAttrs = {
format: "medium",
leaveAgo: true,
};
}
html += autoUpdatingRelativeAge(new Date(attrs.date), dateAttrs);
}
html += `</${tag}>`;
return htmlSafe(html);
});

Datei anzeigen

@ -1,6 +1,5 @@
import DiscourseURL from "discourse/lib/url"; import DiscourseURL from "discourse/lib/url";
import { withPluginApi } from "discourse/lib/plugin-api"; import { withPluginApi } from "discourse/lib/plugin-api";
import CustomWizardNotice from "../models/custom-wizard-notice";
import { isPresent } from "@ember/utils"; import { isPresent } from "@ember/utils";
import { A } from "@ember/array"; import { A } from "@ember/array";
import getUrl from "discourse-common/lib/get-url"; import getUrl from "discourse-common/lib/get-url";
@ -23,50 +22,6 @@ export default {
}; };
withPluginApi("0.8.36", (api) => { 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", { api.modifyClass("component:d-navigation", {
pluginId: "custom-wizard", pluginId: "custom-wizard",
actions: { actions: {

Datei anzeigen

@ -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);
}
},
},
});

Datei anzeigen

@ -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;

Datei anzeigen

@ -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;

Datei anzeigen

@ -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))
),
});
},
});

Datei anzeigen

@ -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();
},
},
});

Datei anzeigen

@ -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>

Datei anzeigen

@ -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>

Datei anzeigen

@ -7,15 +7,8 @@
{{/if}} {{/if}}
{{nav-item route="adminWizardsLogs" label="admin.wizard.log.nav_label"}} {{nav-item route="adminWizardsLogs" label="admin.wizard.log.nav_label"}}
{{nav-item route="adminWizardsManager" label="admin.wizard.manager.nav_label"}} {{nav-item route="adminWizardsManager" label="admin.wizard.manager.nav_label"}}
{{nav-item route="adminWizardsSubscription" label="admin.wizard.subscription.nav_label"}}
<div class="admin-actions"> <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"}}> <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>

Datei anzeigen

@ -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"}}&nbsp;{{format-date notice.dismissed_at leaveAgo="true"}}</span>
{{else if notice.expired}}
<span>{{i18n "admin.wizard.notice.expired_at"}}&nbsp;{{format-date notice.expired_at leaveAgo="true"}}</span>
{{else}}
<span>{{i18n "admin.wizard.notice.active"}}</span>
{{/if}}
</td>

Datei anzeigen

@ -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>

Datei anzeigen

@ -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}}

Datei anzeigen

@ -1,17 +1,19 @@
// discourse-skip-module // discourse-skip-module
document.addEventListener("DOMContentLoaded", function () { if (window.location.pathname.indexOf("/w/") > -1 && Ember.testing) {
document.body.insertAdjacentHTML( document.addEventListener("DOMContentLoaded", function () {
"afterbegin", document.body.insertAdjacentHTML(
` "afterbegin",
<div id="ember-testing-container"><div id="ember-testing"></div></div> `
<style>#ember-testing-container { position: absolute; background: white; bottom: 0; right: 0; width: 640px; height: 384px; overflow: auto; z-index: 9999; border: 1px solid #ccc; } #ember-testing { zoom: 50%; }</style> <div id="ember-testing-container"><div id="ember-testing"></div></div>
` <style>#ember-testing-container { position: absolute; background: white; bottom: 0; right: 0; width: 640px; height: 384px; overflow: auto; z-index: 9999; border: 1px solid #ccc; } #ember-testing { zoom: 50%; }</style>
); `
}); );
});
Object.keys(requirejs.entries).forEach(function (entry) { Object.keys(requirejs.entries).forEach(function (entry) {
if (/\-test/.test(entry)) { if (/\-test/.test(entry)) {
requirejs(entry); requirejs(entry);
} }
}); });
}

Datei anzeigen

@ -54,20 +54,6 @@ en:
after_time: "After time setting is invalid." after_time: "After time setting is invalid."
liquid_syntax_error: "Liquid syntax error in %{attribute}: %{message}" 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: site_settings:
custom_wizard_enabled: "Enable custom wizards." custom_wizard_enabled: "Enable custom wizards."
wizard_redirect_exclude_paths: "Routes excluded from wizard redirects." wizard_redirect_exclude_paths: "Routes excluded from wizard redirects."

Datei anzeigen

@ -45,17 +45,5 @@ Discourse::Application.routes.append do
get 'admin/wizards/manager/export' => 'admin_manager#export' get 'admin/wizards/manager/export' => 'admin_manager#export'
post 'admin/wizards/manager/import' => 'admin_manager#import' post 'admin/wizards/manager/import' => 'admin_manager#import'
delete 'admin/wizards/manager/destroy' => 'admin_manager#destroy' delete 'admin/wizards/manager/destroy' => 'admin_manager#destroy'
get 'admin/wizards/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
end end

Datei anzeigen

@ -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

Datei anzeigen

@ -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

Datei anzeigen

@ -1,240 +1,8 @@
# frozen_string_literal: true
class CustomWizard::Subscription 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? def self.subscribed?
self.new.subscribed?
end end
def self.type 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
end end

Datei anzeigen

@ -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

Datei anzeigen

@ -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

Datei anzeigen

@ -70,15 +70,11 @@ after_initialize do
../app/controllers/custom_wizard/admin/logs.rb ../app/controllers/custom_wizard/admin/logs.rb
../app/controllers/custom_wizard/admin/manager.rb ../app/controllers/custom_wizard/admin/manager.rb
../app/controllers/custom_wizard/admin/custom_fields.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/wizard.rb
../app/controllers/custom_wizard/steps.rb ../app/controllers/custom_wizard/steps.rb
../app/controllers/custom_wizard/realtime_validations.rb ../app/controllers/custom_wizard/realtime_validations.rb
../app/jobs/regular/refresh_api_access_token.rb ../app/jobs/regular/refresh_api_access_token.rb
../app/jobs/regular/set_after_time_wizard.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/template.rb
../lib/custom_wizard/validators/update.rb ../lib/custom_wizard/validators/update.rb
../lib/custom_wizard/action_result.rb ../lib/custom_wizard/action_result.rb
@ -97,11 +93,6 @@ after_initialize do
../lib/custom_wizard/submission.rb ../lib/custom_wizard/submission.rb
../lib/custom_wizard/template.rb ../lib/custom_wizard/template.rb
../lib/custom_wizard/wizard.rb ../lib/custom_wizard/wizard.rb
../lib/custom_wizard/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/api.rb
../lib/custom_wizard/api/authorization.rb ../lib/custom_wizard/api/authorization.rb
../lib/custom_wizard/api/endpoint.rb ../lib/custom_wizard/api/endpoint.rb
@ -122,10 +113,6 @@ after_initialize do
../app/serializers/custom_wizard/log_serializer.rb ../app/serializers/custom_wizard/log_serializer.rb
../app/serializers/custom_wizard/submission_serializer.rb ../app/serializers/custom_wizard/submission_serializer.rb
../app/serializers/custom_wizard/realtime_validation/similar_topics_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/extra_locales_controller.rb
../lib/custom_wizard/extensions/invites_controller.rb ../lib/custom_wizard/extensions/invites_controller.rb
../lib/custom_wizard/extensions/users_controller.rb ../lib/custom_wizard/extensions/users_controller.rb
@ -271,14 +258,6 @@ after_initialize do
"#{serializer_klass}_serializer".classify.constantize.prepend CustomWizardCustomFieldSerializer "#{serializer_klass}_serializer".classify.constantize.prepend CustomWizardCustomFieldSerializer
end 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| reloadable_patch do |plugin|
::TagsController.prepend CustomWizardTagsController ::TagsController.prepend CustomWizardTagsController
::DiscourseTagging.singleton_class.prepend CustomWizardDiscourseTagging ::DiscourseTagging.singleton_class.prepend CustomWizardDiscourseTagging