diff --git a/assets/javascripts/discourse/components/subscription-container.js.es6 b/assets/javascripts/discourse/components/subscription-container.js.es6
index 08498f6f..620c6d88 100644
--- a/assets/javascripts/discourse/components/subscription-container.js.es6
+++ b/assets/javascripts/discourse/components/subscription-container.js.es6
@@ -18,4 +18,4 @@ export default Component.extend({
subscribedTitle(subscribed) {
return `admin.wizard.subscription_container.${subscribed ? 'subscribed' : 'not_subscribed'}.title`;
}
-})
\ No newline at end of file
+});
\ No newline at end of file
diff --git a/assets/javascripts/discourse/components/wizard-notice.js.es6 b/assets/javascripts/discourse/components/wizard-notice.js.es6
index 86a82c94..15da3f35 100644
--- a/assets/javascripts/discourse/components/wizard-notice.js.es6
+++ b/assets/javascripts/discourse/components/wizard-notice.js.es6
@@ -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);
});
diff --git a/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-important-notice.hbs b/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-important-notice.hbs
new file mode 100644
index 00000000..9b01c468
--- /dev/null
+++ b/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-important-notice.hbs
@@ -0,0 +1,3 @@
+{{#if importantNotice}}
+ {{wizard-notice notice=importantNotice importantOnDashboard=true}}
+{{/if}}
diff --git a/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-important-notice.js.es6 b/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-important-notice.js.es6
new file mode 100644
index 00000000..43a2152b
--- /dev/null
+++ b/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-important-notice.js.es6
@@ -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);
+ }
+ }
+};
\ No newline at end of file
diff --git a/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-issue-notice.hbs b/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-issue-notice.hbs
deleted file mode 100644
index a8aad815..00000000
--- a/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-issue-notice.hbs
+++ /dev/null
@@ -1,3 +0,0 @@
-{{#if wizardWarningNotice}}
- {{wizard-notice notice=wizardWarningNotice}}
-{{/if}}
\ No newline at end of file
diff --git a/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-issue-notice.js.es6 b/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-issue-notice.js.es6
deleted file mode 100644
index b92e7897..00000000
--- a/assets/javascripts/discourse/connectors/admin-dashboard-top/custom-wizard-issue-notice.js.es6
+++ /dev/null
@@ -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);
- }
- }
-}
\ No newline at end of file
diff --git a/assets/javascripts/discourse/controllers/admin-wizards-subscription.js.es6 b/assets/javascripts/discourse/controllers/admin-wizards-subscription.js.es6
index 844d5a25..76f16119 100644
--- a/assets/javascripts/discourse/controllers/admin-wizards-subscription.js.es6
+++ b/assets/javascripts/discourse/controllers/admin-wizards-subscription.js.es6
@@ -38,7 +38,7 @@ export default Controller.extend({
unauthorize() {
this.set("unauthorizing", true);
- CustomWizardPro.unauthorize()
+ CustomWizardSubscription.unauthorize()
.then((result) => {
if (result.success) {
this.setProperties({
diff --git a/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6 b/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6
index 4bf50fa9..f53dc2cd 100644
--- a/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6
+++ b/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6
@@ -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);
}
}
diff --git a/assets/javascripts/discourse/models/custom-wizard-notice.js.es6 b/assets/javascripts/discourse/models/custom-wizard-notice.js.es6
index bae81822..a6b47c40 100644
--- a/assets/javascripts/discourse/models/custom-wizard-notice.js.es6
+++ b/assets/javascripts/discourse/models/custom-wizard-notice.js.es6
@@ -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);
}
});
diff --git a/assets/javascripts/discourse/templates/components/subscription-container.hbs b/assets/javascripts/discourse/templates/components/subscription-container.hbs
index 7a02f555..8b012671 100644
--- a/assets/javascripts/discourse/templates/components/subscription-container.hbs
+++ b/assets/javascripts/discourse/templates/components/subscription-container.hbs
@@ -1,5 +1,5 @@
-
{{/if}}
-
+
{{d-icon icon}}
{{title}}
- {{d-icon "calendar-alt"}}
+ {{d-icon "far-clock"}}
{{i18n "admin.wizard.notice.issued"}}
{{format-date notice.created_at leaveAgo="true"}}
+ {{#if notice.updated_at}}
+
+ {{d-icon "calendar-alt"}}
+ {{i18n "admin.wizard.notice.updated"}}
+ {{format-date notice.updated_at leaveAgo="true"}}
+
+ {{/if}}
+
{{d-icon "plug"}}
{{i18n "admin.wizard.notice.plugin"}}
@@ -28,10 +36,16 @@
{{{notice.message}}}
+{{#if importantOnDashboard}}
+
+ {{i18n "admin.wizard.notice.disable_important_on_dashboard"}}
+
+{{/if}}
+
{{#if canDismiss}}
{{#if dismissing}}
{{loading-spinner size="small"}}
{{else}}
{{d-icon "times"}}
{{/if}}
-{{/if}}
\ No newline at end of file
+{{/if}}
diff --git a/assets/stylesheets/admin/admin.scss b/assets/stylesheets/admin/admin.scss
index 2eb32bf3..862f6761 100644
--- a/assets/stylesheets/admin/admin.scss
+++ b/assets/stylesheets/admin/admin.scss
@@ -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);
}
}
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index a63677c6..61e8274c 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -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:
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 63996b02..5fd7c076 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -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 support@thepavilion.io 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 support@thepavilion.io 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 support@thepavilion.io 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."
diff --git a/config/settings.yml b/config/settings.yml
index d88dbaf5..c4337d92 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -15,3 +15,6 @@ plugins:
refresh: true
type: list
list_type: compact
+ wizard_important_notices_on_dashboard:
+ client: true
+ default: true
diff --git a/controllers/custom_wizard/admin/notice.rb b/controllers/custom_wizard/admin/notice.rb
index bb332810..f28240e3 100644
--- a/controllers/custom_wizard/admin/notice.rb
+++ b/controllers/custom_wizard/admin/notice.rb
@@ -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
\ No newline at end of file
+end
diff --git a/coverage/.last_run.json b/coverage/.last_run.json
index 1c721888..a5de03be 100644
--- a/coverage/.last_run.json
+++ b/coverage/.last_run.json
@@ -1,5 +1,5 @@
{
"result": {
- "line": 92.3
+ "line": 92.45
}
}
diff --git a/jobs/scheduled/custom_wizard/update_notices.rb b/jobs/scheduled/custom_wizard/update_notices.rb
index 5194e2b8..25ebdf3b 100644
--- a/jobs/scheduled/custom_wizard/update_notices.rb
+++ b/jobs/scheduled/custom_wizard/update_notices.rb
@@ -6,4 +6,4 @@ class Jobs::CustomWizardUpdateNotices < ::Jobs::Scheduled
def execute(args = {})
CustomWizard::Notice.update
end
-end
\ No newline at end of file
+end
diff --git a/lib/custom_wizard/notice.rb b/lib/custom_wizard/notice.rb
index 096cc579..fb10b724 100644
--- a/lib/custom_wizard/notice.rb
+++ b/lib/custom_wizard/notice.rb
@@ -3,7 +3,14 @@
class CustomWizard::Notice
include ActiveModel::Serialization
+ PLUGIN_STATUS_DOMAINS = {
+ "tests-passed" => "plugins.thepavilion.io",
+ "stable" => "stable.plugins.thepavilion.io"
+ }
+ SUBSCRIPTION_MESSAGES_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)
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: 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 = 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')::text = ?", 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
diff --git a/lib/custom_wizard/notice/connection_error.rb b/lib/custom_wizard/notice/connection_error.rb
new file mode 100644
index 00000000..8b8b944a
--- /dev/null
+++ b/lib/custom_wizard/notice/connection_error.rb
@@ -0,0 +1,81 @@
+# 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.to_json
+ 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
diff --git a/plugin.rb b/plugin.rb
index c3063d29..97d5472b 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -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
diff --git a/serializers/custom_wizard/notice_serializer.rb b/serializers/custom_wizard/notice_serializer.rb
index 310827f7..5564de1f 100644
--- a/serializers/custom_wizard/notice_serializer.rb
+++ b/serializers/custom_wizard/notice_serializer.rb
@@ -6,6 +6,7 @@ class CustomWizard::NoticeSerializer < ApplicationSerializer
:type,
:created_at,
:expired_at,
+ :updated_at,
:dismissed_at,
:retrieved_at,
:dismissable
@@ -17,4 +18,8 @@ class CustomWizard::NoticeSerializer < ApplicationSerializer
def type
CustomWizard::Notice.types.key(object.type)
end
+
+ def messsage
+ PrettyText.cook(object.message)
+ end
end
diff --git a/spec/components/custom_wizard/notice_spec.rb b/spec/components/custom_wizard/notice_spec.rb
index 373d2e31..b51305e1 100644
--- a/spec/components/custom_wizard/notice_spec.rb
+++ b/spec/components/custom_wizard/notice_spec.rb
@@ -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.message).to eq(PrettyText.cook(I18n.t("wizard.notice.compatibility_issue", server: described_class.plugin_status_domain)))
+ expect(notice.type).to eq(described_class.types[:plugin_status_warning])
+ expect(notice.message).to eq(I18n.t("wizard.notice.compatibility_issue", domain: described_class.plugin_status_domain))
expect(notice.created_at.to_datetime).to be_within(1.second).of (plugin_status[:status_changed_at].to_datetime)
end
-
- it "expires 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
\ No newline at end of file
+
+ 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
diff --git a/spec/fixtures/sprockets/require_tree_discourse_empty.js b/spec/fixtures/sprockets/require_tree_discourse_empty.js
index df264ec5..953c5ec4 100644
--- a/spec/fixtures/sprockets/require_tree_discourse_empty.js
+++ b/spec/fixtures/sprockets/require_tree_discourse_empty.js
@@ -1 +1 @@
-//= require_tree_discourse
\ No newline at end of file
+//= require_tree_discourse
\ No newline at end of file