Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-11-22 09:20:29 +01:00
DEV: Add notice specs and UI updates
Dieser Commit ist enthalten in:
Ursprung
084c6f4a7a
Commit
925c8c009a
23 geänderte Dateien mit 306 neuen und 129 gelöschten Zeilen
|
@ -18,4 +18,4 @@ export default Component.extend({
|
|||
subscribedTitle(subscribed) {
|
||||
return `admin.wizard.subscription_container.${subscribed ? 'subscribed' : 'not_subscribed'}.title`;
|
||||
}
|
||||
})
|
||||
});
|
|
@ -1,10 +1,10 @@
|
|||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { notEmpty, not } from "@ember/object/computed";
|
||||
import { not, notEmpty } from "@ember/object/computed";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: [':wizard-notice', 'notice.type', 'dismissed', 'expired'],
|
||||
classNameBindings: [':wizard-notice', 'notice.type', 'dismissed', 'expired', 'resolved'],
|
||||
showFull: false,
|
||||
resolved: notEmpty('notice.expired_at'),
|
||||
dismissed: notEmpty('notice.dismissed_at'),
|
||||
|
@ -18,14 +18,16 @@ export default Component.extend({
|
|||
@discourseComputed('notice.type')
|
||||
icon(type) {
|
||||
return {
|
||||
warning: 'exclamation-circle',
|
||||
plugin_status_warning: 'exclamation-circle',
|
||||
plugin_status_connection_error: 'bolt',
|
||||
subscription_messages_connection_error: 'bolt',
|
||||
info: 'info-circle'
|
||||
}[type];
|
||||
},
|
||||
|
||||
actions: {
|
||||
dismiss() {
|
||||
this.set('dismissing', true)
|
||||
this.set('dismissing', true);
|
||||
this.notice.dismiss().then(() => {
|
||||
this.set('dismissing', false);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
{{#if importantNotice}}
|
||||
{{wizard-notice notice=importantNotice importantOnDashboard=true}}
|
||||
{{/if}}
|
|
@ -0,0 +1,16 @@
|
|||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
|
||||
export default {
|
||||
shouldRender(attrs, ctx) {
|
||||
return ctx.siteSettings.wizard_important_notices_on_dashboard;
|
||||
},
|
||||
|
||||
setupComponent() {
|
||||
const controller = getOwner(this).lookup('controller:admin-dashboard');
|
||||
const importantNotice = controller.get('customWizardImportantNotice');
|
||||
|
||||
if (importantNotice) {
|
||||
this.set('importantNotice', importantNotice);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,3 +0,0 @@
|
|||
{{#if wizardWarningNotice}}
|
||||
{{wizard-notice notice=wizardWarningNotice}}
|
||||
{{/if}}
|
|
@ -1,12 +0,0 @@
|
|||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
|
||||
export default {
|
||||
setupComponent() {
|
||||
const controller = getOwner(this).lookup('controller:admin-dashboard')
|
||||
const wizardWarningNotice = controller.get('wizardWarningNotice');
|
||||
|
||||
if (wizardWarningNotice) {
|
||||
this.set('wizardWarningNotice', wizardWarningNotice);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,7 +38,7 @@ export default Controller.extend({
|
|||
unauthorize() {
|
||||
this.set("unauthorizing", true);
|
||||
|
||||
CustomWizardPro.unauthorize()
|
||||
CustomWizardSubscription.unauthorize()
|
||||
.then((result) => {
|
||||
if (result.success) {
|
||||
this.setProperties({
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import DiscourseURL from "discourse/lib/url";
|
||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import CustomWizardNotice from "../models/custom-wizard-notice";
|
||||
import { A } from "@ember/array";
|
||||
|
||||
|
@ -31,12 +30,13 @@ export default {
|
|||
});
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
setupController(controller) {
|
||||
if (this.notices) {
|
||||
let warningNotices = this.notices.filter(n => n.type === 'warning');
|
||||
let pluginStatusConnectionError = this.notices.filter(n => n.type === 'plugin_status_connection_error')[0];
|
||||
let pluginStatusWarning = this.notices.filter(n => n.type === 'plugin_status_warning')[0];
|
||||
|
||||
if (warningNotices.length) {
|
||||
controller.set('wizardWarningNotice', warningNotices[0]);
|
||||
if (pluginStatusConnectionError || pluginStatusWarning) {
|
||||
controller.set('customWizardImportantNotice', pluginStatusConnectionError || pluginStatusWarning);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,13 +10,13 @@ CustomWizardNotice.reopen({
|
|||
if (result.success) {
|
||||
this.set('dismissed_at', result.dismissed_at);
|
||||
}
|
||||
}).catch(popupAjaxError)
|
||||
}).catch(popupAjaxError);
|
||||
}
|
||||
});
|
||||
|
||||
CustomWizardNotice.reopenClass({
|
||||
list() {
|
||||
return ajax('/admin/wizards/notice').catch(popupAjaxError)
|
||||
return ajax('/admin/wizards/notice').catch(popupAjaxError);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class=subscription-header>
|
||||
<h3>{{i18n 'admin.wizard.subscription_container.title'}}</h3>
|
||||
<div class="subscription-header">
|
||||
<h3>{{i18n "admin.wizard.subscription_container.title"}}</h3>
|
||||
|
||||
<a href="/admin/wizards/subscription" title={{i18n subscribedTitle}}>
|
||||
{{d-icon subscribedIcon}}
|
||||
|
@ -9,4 +9,4 @@
|
|||
|
||||
<div class="subscription-settings">
|
||||
{{yield}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,18 +6,26 @@
|
|||
{{format-date notice.expired_at leaveAgo="true"}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
|
||||
<div class="notice-title notice-badge" title={{title}}>
|
||||
{{d-icon icon}}
|
||||
<span>{{title}}</span>
|
||||
</div>
|
||||
|
||||
<div class="notice-created-at notice-badge" title={{notice.created_at}}>
|
||||
{{d-icon "calendar-alt"}}
|
||||
{{d-icon "far-clock"}}
|
||||
<span class="notice-issued">{{i18n "admin.wizard.notice.issued"}}</span>
|
||||
{{format-date notice.created_at leaveAgo="true"}}
|
||||
</div>
|
||||
|
||||
{{#if notice.updated_at}}
|
||||
<div class="notice-updated-at notice-badge" title={{notice.updated_at}}>
|
||||
{{d-icon "calendar-alt"}}
|
||||
<span class="notice-updated">{{i18n "admin.wizard.notice.updated"}}</span>
|
||||
{{format-date notice.updated_at leaveAgo="true"}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="notice-plugin notice-badge" title={{i18n "admin.wizard.notice.plugin"}}>
|
||||
{{d-icon "plug"}}
|
||||
<span>{{i18n "admin.wizard.notice.plugin"}}</span>
|
||||
|
@ -28,10 +36,16 @@
|
|||
{{{notice.message}}}
|
||||
</div>
|
||||
|
||||
{{#if importantOnDashboard}}
|
||||
<a href="/admin/site_settings/category/all_results?filter=wizard_important_notices_on_dashboard" class="disable-important">
|
||||
{{i18n "admin.wizard.notice.disable_important_on_dashboard"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if canDismiss}}
|
||||
{{#if dismissing}}
|
||||
{{loading-spinner size="small"}}
|
||||
{{else}}
|
||||
<a {{action "dismiss"}} role="button" class="dismiss-notice">{{d-icon "times"}}</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
|
|
@ -911,13 +911,18 @@
|
|||
padding: 1em;
|
||||
margin-bottom: 1em;
|
||||
border: 1px solid var(--primary);
|
||||
border-radius: 4px;
|
||||
position: relative;
|
||||
|
||||
&.dismissed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.resolved .notice-badge:not(.notice-expired-at),
|
||||
&.resolved a,
|
||||
&.resolved p {
|
||||
color: var(--primary-medium) !important;
|
||||
}
|
||||
|
||||
.d-icon {
|
||||
margin-right: .4em;
|
||||
}
|
||||
|
@ -931,7 +936,6 @@
|
|||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0 .5em;
|
||||
border-radius: 4px;
|
||||
margin-right: 1em;
|
||||
font-size: .9em;
|
||||
line-height: 25px;
|
||||
|
@ -957,7 +961,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
.notice-issued {
|
||||
.notice-issued,
|
||||
.notice-resolved {
|
||||
margin-right: .3em;
|
||||
}
|
||||
|
||||
|
@ -976,6 +981,13 @@
|
|||
position: absolute;
|
||||
top: 1em;
|
||||
right: 1em;
|
||||
color: var(--primary);
|
||||
color: var(--primary-medium);
|
||||
}
|
||||
|
||||
.disable-important {
|
||||
position: absolute;
|
||||
right: 3em;
|
||||
top: 1em;
|
||||
color: var(--primary-medium);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -485,9 +485,13 @@ en:
|
|||
notice:
|
||||
plugin: Custom Wizard Plugin
|
||||
issued: Issued
|
||||
update: Updated
|
||||
resolved: Resolved
|
||||
title:
|
||||
warning: Warning Notice
|
||||
plugin_status_warning: Warning Notice
|
||||
plugin_status_connection_error: Connection Notice
|
||||
subscription_messages_connection_error: Connection Notice
|
||||
disable_important_on_dashboard: disable
|
||||
|
||||
wizard_js:
|
||||
group:
|
||||
|
|
|
@ -53,16 +53,22 @@ en:
|
|||
subscription: "%{type} %{property} is subscription only"
|
||||
|
||||
notice:
|
||||
connection_error: "Failed to connect to [%{server}](http://%{server})"
|
||||
connection_error: "Failed to connect to http://%{domain}"
|
||||
compatibility_issue: >
|
||||
The Custom Wizard Plugin may have a compatibility issue with the latest version of Discourse.
|
||||
Please check the Custom Wizard Plugin status on [%{server}](http://%{server}) before updating Discourse.
|
||||
plugin_status_connection_error_limit: >
|
||||
We're unable to connect to the plugin status server to determine whether there are any compatibility issues with the latest version of Discourse.
|
||||
Please contact <a href="mailto:support@thepavilion.io">support@thepavilion.io</a> for further assistance.
|
||||
The Custom Wizard Plugin has a compatibility issue with the latest version of Discourse.
|
||||
Please check the Custom Wizard Plugin status on [%{domain}](http://%{domain}) before updating Discourse.
|
||||
plugin_status:
|
||||
connection_error_limit: >
|
||||
We're unable to connect to the Pavilion Plugin Status Server. Please check the Custom Wizard Plugin status on [%{domain}](http://%{domain}) before updating Discourse or the plugin.
|
||||
If this connection issue persists please contact <a href="mailto:support@thepavilion.io">support@thepavilion.io</a> for further assistance.
|
||||
subscription_messages:
|
||||
connection_error_limit: >
|
||||
We're unable to connect to the Pavilion Subscription Server. This will not affect the operation of the plugin.
|
||||
If this connection issue persists please 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."
|
||||
wizard_recognised_image_upload_formats: "File types which will result in upload displaying an image preview"
|
||||
wizard_apis_enabled: "Enable API features (experimental)."
|
||||
wizard_important_notices_on_dashboard: "Show important notices about the custom wizard plugin on the admin dashboard."
|
||||
|
|
|
@ -17,4 +17,7 @@ plugins:
|
|||
list_type: compact
|
||||
wizard_apis_enabled:
|
||||
client: true
|
||||
default: false
|
||||
default: false
|
||||
wizard_important_notices_on_dashboard:
|
||||
client: true
|
||||
default: true
|
|
@ -4,7 +4,7 @@ class CustomWizard::AdminNoticeController < CustomWizard::AdminController
|
|||
before_action :find_notice, only: [:dismiss]
|
||||
|
||||
def index
|
||||
render_serialized(CustomWizard::Notice.list, CustomWizard::NoticeSerializer)
|
||||
render_serialized(CustomWizard::Notice.list(include_recently_expired: true), CustomWizard::NoticeSerializer)
|
||||
end
|
||||
|
||||
def dismiss
|
||||
|
@ -19,4 +19,4 @@ class CustomWizard::AdminNoticeController < CustomWizard::AdminController
|
|||
@notice = CustomWizard::Notice.find(params[:notice_id])
|
||||
raise Discourse::InvalidParameters.new(:notice_id) unless @notice
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,4 +6,4 @@ class Jobs::CustomWizardUpdateNotices < ::Jobs::Scheduled
|
|||
def execute(args = {})
|
||||
CustomWizard::Notice.update
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,7 +3,14 @@
|
|||
class CustomWizard::Notice
|
||||
include ActiveModel::Serialization
|
||||
|
||||
PLUGIN_STATUS_DOMAINS = {
|
||||
"tests-passed" => "try.thepavilion.io",
|
||||
"stable" => "stable.try.thepavilion.io"
|
||||
}
|
||||
SUBSCRIPTION_MESSAGES_DOMAIN = "thepavilion.io"
|
||||
LOCALHOST_DOMAIN = "localhost:3000"
|
||||
PLUGIN_STATUSES_TO_WARN = %w(incompatible tests_failing)
|
||||
CHECK_PLUGIN_STATUS_ON_BRANCH = %w(tests-passed main stable)
|
||||
|
||||
attr_reader :id,
|
||||
:message,
|
||||
|
@ -11,6 +18,7 @@ class CustomWizard::Notice
|
|||
:created_at
|
||||
|
||||
attr_accessor :retrieved_at,
|
||||
:updated_at,
|
||||
:dismissed_at,
|
||||
:expired_at
|
||||
|
||||
|
@ -19,6 +27,7 @@ class CustomWizard::Notice
|
|||
@message = attrs[:message]
|
||||
@type = attrs[:type].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]
|
||||
|
@ -52,7 +61,6 @@ class CustomWizard::Notice
|
|||
attrs = {
|
||||
expired_at: expired_at,
|
||||
created_at: created_at,
|
||||
expired_at: expired_at,
|
||||
message: message,
|
||||
type: type
|
||||
}
|
||||
|
@ -67,14 +75,9 @@ class CustomWizard::Notice
|
|||
def self.types
|
||||
@types ||= Enum.new(
|
||||
info: 0,
|
||||
warning: 1
|
||||
)
|
||||
end
|
||||
|
||||
def self.connection_types
|
||||
@connection_types ||= Enum.new(
|
||||
plugin_status: 0,
|
||||
subscription: 1
|
||||
plugin_status_warning: 1,
|
||||
plugin_status_connection_error: 2,
|
||||
subscription_messages_connection_error: 3
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -82,23 +85,20 @@ class CustomWizard::Notice
|
|||
notices = []
|
||||
|
||||
if !skip_subscription
|
||||
subscription_messages = request(subscription_messages_url)
|
||||
subscription_messages = request(:subscription_messages)
|
||||
|
||||
if subscription_messages.present?
|
||||
subscription_notices = convert_subscription_messages_to_notices(subscription_messages[:messages])
|
||||
notices.push(*subscription_notices)
|
||||
end
|
||||
end
|
||||
|
||||
if !skip_plugin && (Discourse.git_branch === 'tests-passed' || (Rails.env.test? || Rails.env.development?))
|
||||
plugin_status = request(plugin_status_url)
|
||||
if !skip_plugin && request_plugin_status?
|
||||
plugin_status = request(:plugin_status)
|
||||
|
||||
if plugin_status.present? && plugin_status[:status].present? && plugin_status[:status].is_a?(Hash)
|
||||
plugin_notice = convert_plugin_status_to_notice(plugin_status[:status])
|
||||
notices.push(plugin_notice) if plugin_notice
|
||||
|
||||
expire_connection_errors(connection_types[:plugin_status])
|
||||
else
|
||||
create_connection_error(connection_types[:plugin_status])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -107,14 +107,6 @@ class CustomWizard::Notice
|
|||
notice.retrieved_at = Time.now
|
||||
notice.save
|
||||
end
|
||||
|
||||
if reached_connection_error_limit(connection_types[:plugin_status])
|
||||
new(
|
||||
message: I18n.t("wizard.notice.plugin_status_connection_error_limit"),
|
||||
type: types[:warning],
|
||||
created_at: Time.now
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def self.convert_subscription_messages_to_notices(messages)
|
||||
|
@ -133,19 +125,46 @@ class CustomWizard::Notice
|
|||
|
||||
if PLUGIN_STATUSES_TO_WARN.include?(plugin_status[:status])
|
||||
notice = {
|
||||
message: PrettyText.cook(I18n.t('wizard.notice.compatibility_issue', server: plugin_status_domain)),
|
||||
type: types[:warning],
|
||||
message: PrettyText.cook(I18n.t('wizard.notice.compatibility_issue', domain: plugin_status_domain)),
|
||||
type: types[:plugin_status_warning],
|
||||
created_at: plugin_status[:status_changed_at]
|
||||
}
|
||||
else
|
||||
list(types[:warning]).each(&:expire)
|
||||
expire_notices(types[:plugin_status_warning])
|
||||
end
|
||||
|
||||
notice
|
||||
end
|
||||
|
||||
def self.notify_connection_errors(connection_type_key)
|
||||
domain = self.send("#{connection_type_key.to_s}_domain")
|
||||
message = PrettyText.cook(I18n.t("wizard.notice.#{connection_type_key.to_s}.connection_error_limit", domain: domain))
|
||||
notices = list(type: types[:connection_error], message: message)
|
||||
|
||||
if notices.any?
|
||||
notice = notices.first
|
||||
notice.updated_at = Time.now
|
||||
notice.save
|
||||
else
|
||||
notice = new(
|
||||
message: message,
|
||||
type: types["#{connection_type_key}_connection_error".to_sym],
|
||||
created_at: Time.now
|
||||
)
|
||||
notice.save
|
||||
end
|
||||
end
|
||||
|
||||
def self.expire_notices(type)
|
||||
list(type: type).each(&:expire)
|
||||
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_messages_domain
|
||||
"localhost:3000"
|
||||
(Rails.env.test? || Rails.env.development?) ? LOCALHOST_DOMAIN : SUBSCRIPTION_MESSAGES_DOMAIN
|
||||
end
|
||||
|
||||
def self.subscription_messages_url
|
||||
|
@ -153,25 +172,34 @@ class CustomWizard::Notice
|
|||
end
|
||||
|
||||
def self.plugin_status_domain
|
||||
"localhost:4200"
|
||||
return LOCALHOST_DOMAIN if (Rails.env.test? || Rails.env.development?)
|
||||
PLUGIN_STATUS_DOMAINS[Discourse.git_branch]
|
||||
end
|
||||
|
||||
def self.plugin_status_url
|
||||
"http://#{plugin_status_domain}/plugin-manager/status/discourse-custom-wizard"
|
||||
end
|
||||
|
||||
def self.request(url)
|
||||
|
||||
def self.request(type)
|
||||
url = self.send("#{type.to_s}_url")
|
||||
response = Excon.get(url)
|
||||
connection_error = CustomWizard::Notice::ConnectionError.new(type)
|
||||
|
||||
if response.status == 200
|
||||
connection_error.expire!
|
||||
expire_notices(types["#{type}_connection_error".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(type) if connection_error.reached_limit?
|
||||
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
@ -180,10 +208,6 @@ class CustomWizard::Notice
|
|||
"#{CustomWizard::PLUGIN_NAME}_notice"
|
||||
end
|
||||
|
||||
def self.namespace_connection
|
||||
"#{CustomWizard::PLUGIN_NAME}_notice_connection"
|
||||
end
|
||||
|
||||
def self.find(id)
|
||||
raw = PluginStore.get(namespace, id)
|
||||
new(raw.symbolize_keys) if raw.present?
|
||||
|
@ -193,42 +217,16 @@ class CustomWizard::Notice
|
|||
PluginStore.set(namespace, id, raw_notice)
|
||||
end
|
||||
|
||||
def self.plugin_status_connection_error_limit
|
||||
5
|
||||
end
|
||||
|
||||
def self.list_connection_query(type)
|
||||
query = PluginStoreRow.where(plugin_name: namespace_connection)
|
||||
query.where("(value::json->>'type')::integer = ?", type)
|
||||
end
|
||||
|
||||
def self.expire_connection_errors(type)
|
||||
list_connection_query(type).update_all("value = jsonb_set(value::jsonb, '{ expired_at }', (to_char(current_timestamp, 'HH12:MI:SS'))::jsonb)")
|
||||
end
|
||||
|
||||
def self.create_connection_error(type)
|
||||
id = SecureRandom.hex(16)
|
||||
attrs = {
|
||||
message: I18n.t("wizard.notice.connection_error", domain: self.send("#{type}_domain")),
|
||||
type: type,
|
||||
created_at: Time.now
|
||||
}
|
||||
PluginStore.set(namespace_connection, id, attrs)
|
||||
end
|
||||
|
||||
def self.reached_connection_error_limit(type)
|
||||
list_connection_query(type).size >= self.send("#{connection_types.key(type)}_connection_error_limit")
|
||||
end
|
||||
|
||||
def self.list_query(type = nil)
|
||||
def self.list_query(type: nil, message: nil, include_recently_expired: false)
|
||||
query = PluginStoreRow.where(plugin_name: namespace)
|
||||
query = query.where("(value::json->>'expired_at') IS NULL OR (value::json->>'expired_at')::date > now()::date - 1")
|
||||
query = query.where("(value::json->>'expired_at') IS NULL#{include_recently_expired ? " OR (value::json->>'expired_at')::date > now()::date - 1" : ""}")
|
||||
query = query.where("(value::json->>'type')::integer = ?", type) if type
|
||||
query = query.where("(value::json->>'message') = ?", message) if message
|
||||
query.order("value::json->>'created_at' DESC")
|
||||
end
|
||||
|
||||
def self.list(type = nil)
|
||||
list_query(type)
|
||||
def self.list(type: nil, message: nil, include_recently_expired: false)
|
||||
list_query(type: type, message: message, include_recently_expired: include_recently_expired)
|
||||
.map { |r| self.new(JSON.parse(r.value).symbolize_keys) }
|
||||
end
|
||||
end
|
||||
|
|
82
lib/custom_wizard/notice/connection_error.rb
Normale Datei
82
lib/custom_wizard/notice/connection_error.rb
Normale Datei
|
@ -0,0 +1,82 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CustomWizard::Notice::ConnectionError
|
||||
|
||||
attr_reader :type_key
|
||||
|
||||
def initialize(type_key)
|
||||
@type_key = type_key
|
||||
end
|
||||
|
||||
def create!
|
||||
id = "#{type_key.to_s}_error"
|
||||
|
||||
if attrs = PluginStore.get(namespace, id)
|
||||
attrs['updated_at'] = Time.now
|
||||
attrs['count'] = attrs['count'].to_i + 1
|
||||
else
|
||||
domain = CustomWizard::Notice.send("#{type_key.to_s}_domain")
|
||||
attrs = {
|
||||
message: I18n.t("wizard.notice.connection_error", domain: domain),
|
||||
type: self.class.types[type_key],
|
||||
created_at: Time.now,
|
||||
count: 1
|
||||
}
|
||||
end
|
||||
|
||||
PluginStore.set(namespace, id, attrs)
|
||||
|
||||
@errors = nil
|
||||
end
|
||||
|
||||
def expire!
|
||||
if errors.exists?
|
||||
errors.each do |error_row|
|
||||
error = JSON.parse(error_row.value)
|
||||
error['expired_at'] = Time.now
|
||||
error_row.value = error
|
||||
error_row.save
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.types
|
||||
@types ||= Enum.new(
|
||||
plugin_status: 0,
|
||||
subscription_messages: 1
|
||||
)
|
||||
end
|
||||
|
||||
def plugin_status_limit
|
||||
5
|
||||
end
|
||||
|
||||
def subscription_messages_limit
|
||||
10
|
||||
end
|
||||
|
||||
def limit
|
||||
self.send("#{type_key.to_s}_limit")
|
||||
end
|
||||
|
||||
def reached_limit?
|
||||
return false unless errors.exists?
|
||||
current_error['count'].to_i >= limit
|
||||
end
|
||||
|
||||
def current_error
|
||||
JSON.parse(errors.first.value)
|
||||
end
|
||||
|
||||
def namespace
|
||||
"#{CustomWizard::PLUGIN_NAME}_notice_connection"
|
||||
end
|
||||
|
||||
def errors
|
||||
@errors ||= begin
|
||||
query = PluginStoreRow.where(plugin_name: namespace)
|
||||
query = query.where("(value::json->>'type')::integer = ?", self.class.types[type_key])
|
||||
query.where("(value::json->>'expired_at') IS NULL")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -40,7 +40,7 @@ if respond_to?(:register_svg_icon)
|
|||
register_svg_icon "comment-alt"
|
||||
register_svg_icon "far-life-ring"
|
||||
register_svg_icon "arrow-right"
|
||||
register_svg_icon "shield-virus"
|
||||
register_svg_icon "bolt"
|
||||
end
|
||||
|
||||
class ::Sprockets::DirectiveProcessor
|
||||
|
@ -98,6 +98,7 @@ after_initialize do
|
|||
../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
|
||||
|
@ -242,10 +243,9 @@ after_initialize do
|
|||
end
|
||||
|
||||
AdminDashboardData.add_problem_check do
|
||||
warning_notices = CustomWizard::Notice.list(CustomWizard::Notice.types[:warning])
|
||||
warning_notices = CustomWizard::Notice.list(type: CustomWizard::Notice.types[:plugin_status_warning])
|
||||
warning_notices.any? ? ActionView::Base.full_sanitizer.sanitize(warning_notices.first.message, tags: %w(a)) : nil
|
||||
end
|
||||
|
||||
Jobs.enqueue(:custom_wizard_update_notices)
|
||||
DiscourseEvent.trigger(:custom_wizard_ready)
|
||||
end
|
||||
|
|
|
@ -6,6 +6,7 @@ class CustomWizard::NoticeSerializer < ApplicationSerializer
|
|||
:type,
|
||||
:created_at,
|
||||
:expired_at,
|
||||
:updated_at,
|
||||
:dismissed_at,
|
||||
:retrieved_at,
|
||||
:dismissable
|
||||
|
|
|
@ -33,13 +33,13 @@ describe CustomWizard::Notice do
|
|||
expect(notice.message).to eq(subscription_message[:message])
|
||||
expect(notice.created_at.to_datetime).to be_within(1.second).of (subscription_message[:created_at].to_datetime)
|
||||
end
|
||||
|
||||
|
||||
it "expires notice if subscription message is expired" do
|
||||
subscription_message[:expired_at] = Time.now
|
||||
stub_request(:get, described_class.subscription_messages_url).to_return(status: 200, body: { messages: [subscription_message] }.to_json)
|
||||
described_class.update(skip_plugin: true)
|
||||
|
||||
notice = described_class.list.first
|
||||
notice = described_class.list(include_recently_expired: true).first
|
||||
expect(notice.expired?).to eq(true)
|
||||
end
|
||||
end
|
||||
|
@ -51,20 +51,20 @@ describe CustomWizard::Notice do
|
|||
described_class.update(skip_subscription: true)
|
||||
end
|
||||
|
||||
it "converts plugin statuses to warn into notices" do
|
||||
it "converts warning into notice" do
|
||||
notice = described_class.list.first
|
||||
expect(notice.type).to eq(described_class.types[:warning])
|
||||
expect(notice.type).to eq(described_class.types[:plugin_status_warning])
|
||||
expect(notice.message).to eq(PrettyText.cook(I18n.t("wizard.notice.compatibility_issue", server: described_class.plugin_status_domain)))
|
||||
expect(notice.created_at.to_datetime).to be_within(1.second).of (plugin_status[:status_changed_at].to_datetime)
|
||||
end
|
||||
|
||||
it "expires unexpired warning notices if status is recommended or compatible" do
|
||||
|
||||
it "expires warning notices if status is recommended or compatible" do
|
||||
plugin_status[:status] = 'compatible'
|
||||
plugin_status[:status_changed_at] = Time.now
|
||||
stub_request(:get, described_class.plugin_status_url).to_return(status: 200, body: { status: plugin_status }.to_json)
|
||||
described_class.update(skip_subscription: true)
|
||||
|
||||
notice = described_class.list(described_class.types[:warning]).first
|
||||
notice = described_class.list(type: described_class.types[:plugin_status_warning], include_recently_expired: true).first
|
||||
expect(notice.expired?).to eq(true)
|
||||
end
|
||||
end
|
||||
|
@ -75,6 +75,57 @@ describe CustomWizard::Notice do
|
|||
stub_request(:get, described_class.plugin_status_url).to_return(status: 200, body: { status: plugin_status }.to_json)
|
||||
|
||||
described_class.update
|
||||
expect(described_class.list.length).to eq(2)
|
||||
expect(described_class.list(include_recently_expired: true).length).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
context "connection errors" do
|
||||
before do
|
||||
freeze_time
|
||||
end
|
||||
|
||||
it "creates an error if connection to notice server fails" do
|
||||
stub_request(:get, described_class.plugin_status_url).to_return(status: 400, body: { status: plugin_status }.to_json)
|
||||
described_class.update(skip_subscription: true)
|
||||
|
||||
error = CustomWizard::Notice::ConnectionError.new(:plugin_status)
|
||||
expect(error.errors.exists?).to eq(true)
|
||||
end
|
||||
|
||||
it "only creates one connection error per type at a time" do
|
||||
stub_request(:get, described_class.subscription_messages_url).to_return(status: 400, body: { messages: [subscription_message] }.to_json)
|
||||
stub_request(:get, described_class.plugin_status_url).to_return(status: 400, body: { status: plugin_status }.to_json)
|
||||
|
||||
5.times { described_class.update }
|
||||
|
||||
plugin_status_errors = CustomWizard::Notice::ConnectionError.new(:plugin_status)
|
||||
subscription_message_errors = CustomWizard::Notice::ConnectionError.new(:subscription_messages)
|
||||
|
||||
expect(plugin_status_errors.errors.length).to eq(1)
|
||||
expect(subscription_message_errors.errors.length).to eq(1)
|
||||
end
|
||||
|
||||
it "creates a connection error notice if connection errors reach limit" do
|
||||
stub_request(:get, described_class.plugin_status_url).to_return(status: 400, body: { status: plugin_status }.to_json)
|
||||
|
||||
error = CustomWizard::Notice::ConnectionError.new(:plugin_status)
|
||||
error.limit.times { described_class.update(skip_subscription: true) }
|
||||
notice = described_class.list(type: described_class.types[:plugin_status_connection_error]).first
|
||||
|
||||
expect(error.current_error['count']).to eq(error.limit)
|
||||
expect(notice.type).to eq(described_class.types[:plugin_status_connection_error])
|
||||
end
|
||||
|
||||
it "expires a connection error notice if connection succeeds" do
|
||||
stub_request(:get, described_class.plugin_status_url).to_return(status: 400, body: { status: plugin_status }.to_json)
|
||||
error = CustomWizard::Notice::ConnectionError.new(:plugin_status)
|
||||
error.limit.times { described_class.update(skip_subscription: true) }
|
||||
|
||||
stub_request(:get, described_class.plugin_status_url).to_return(status: 200, body: { status: plugin_status }.to_json)
|
||||
described_class.update(skip_subscription: true)
|
||||
notice = described_class.list(type: described_class.types[:plugin_status_connection_error], include_recently_expired: true).first
|
||||
|
||||
expect(notice.type).to eq(described_class.types[:plugin_status_connection_error])
|
||||
expect(notice.expired_at.present?).to eq(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1 +1 @@
|
|||
//= require_tree_discourse
|
||||
//= require_tree_discourse
|
Laden …
In neuem Issue referenzieren