2021-09-24 11:58:42 +02:00
# frozen_string_literal: true
class CustomWizard :: Notice
include ActiveModel :: Serialization
2021-10-05 14:54:06 +02:00
PLUGIN_STATUS_DOMAINS = {
2021-10-19 10:08:03 +02:00
" tests-passed " = > " plugins.discourse.pavilion.tech " ,
" stable " = > " stable.plugins.discourse.pavilion.tech "
2021-10-05 14:54:06 +02:00
}
2021-11-01 14:52:29 +01:00
SUBSCRIPTION_MESSAGE_DOMAIN = " test.thepavilion.io "
2021-10-05 14:54:06 +02:00
LOCALHOST_DOMAIN = " localhost:3000 "
2021-09-24 11:58:42 +02:00
PLUGIN_STATUSES_TO_WARN = %w( incompatible tests_failing )
2021-10-05 14:54:06 +02:00
CHECK_PLUGIN_STATUS_ON_BRANCH = %w( tests-passed main stable )
2021-11-01 14:52:29 +01:00
PAGE_LIMIT = 30
2021-09-24 11:58:42 +02:00
attr_reader :id ,
2021-11-01 14:52:29 +01:00
:title ,
2021-09-24 11:58:42 +02:00
:message ,
:type ,
2021-11-01 14:52:29 +01:00
:archetype ,
2021-09-24 11:58:42 +02:00
:created_at
attr_accessor :retrieved_at ,
2021-10-05 14:54:06 +02:00
:updated_at ,
2021-09-24 11:58:42 +02:00
:dismissed_at ,
2021-11-01 14:52:29 +01:00
:expired_at ,
:hidden_at
2021-09-24 11:58:42 +02:00
def initialize ( attrs )
2021-11-01 14:52:29 +01:00
@id = self . class . generate_notice_id ( attrs [ :title ] , attrs [ :created_at ] )
@title = attrs [ :title ]
2021-09-24 11:58:42 +02:00
@message = attrs [ :message ]
@type = attrs [ :type ] . to_i
2021-11-01 14:52:29 +01:00
@archetype = attrs [ :archetype ] . to_i
2021-09-24 11:58:42 +02:00
@created_at = attrs [ :created_at ]
2021-10-05 14:54:06 +02:00
@updated_at = attrs [ :updated_at ]
2021-09-24 11:58:42 +02:00
@retrieved_at = attrs [ :retrieved_at ]
@dismissed_at = attrs [ :dismissed_at ]
@expired_at = attrs [ :expired_at ]
2021-11-01 14:52:29 +01:00
@hidden_at = attrs [ :hidden_at ]
2021-09-24 11:58:42 +02:00
end
2021-11-01 14:52:29 +01:00
def dismiss!
2021-09-24 11:58:42 +02:00
if dismissable?
self . dismissed_at = Time . now
self . save
2021-11-01 14:52:29 +01:00
self . class . publish_notice_count
2021-09-24 11:58:42 +02:00
end
end
2021-11-01 14:52:29 +01:00
def hide!
if can_hide?
self . hidden_at = Time . now
self . save
self . class . publish_notice_count
end
end
def expire!
if ! expired?
self . expired_at = Time . now
self . save
self . class . publish_notice_count
end
2021-09-24 11:58:42 +02:00
end
def expired?
expired_at . present?
end
def dismissed?
dismissed_at . present?
end
def dismissable?
2021-11-01 14:52:29 +01:00
! 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 ]
)
2021-09-24 11:58:42 +02:00
end
def save
attrs = {
expired_at : expired_at ,
2021-11-01 14:52:29 +01:00
updated_at : updated_at ,
retrieved_at : retrieved_at ,
2021-09-24 11:58:42 +02:00
created_at : created_at ,
2021-11-01 14:52:29 +01:00
hidden_at : hidden_at ,
title : title ,
2021-09-24 11:58:42 +02:00
message : message ,
2021-11-01 14:52:29 +01:00
type : type ,
archetype : archetype
2021-09-24 11:58:42 +02:00
}
if current = self . class . find ( self . id )
attrs [ :dismissed_at ] = current . dismissed_at || self . dismissed_at
end
self . class . store ( id , attrs )
end
def self . types
@types || = Enum . new (
info : 0 ,
2021-11-01 14:52:29 +01:00
warning : 1 ,
connection_error : 2
)
end
def self . archetypes
@archetypes || = Enum . new (
subscription_message : 0 ,
plugin_status : 1
2021-09-24 11:58:42 +02:00
)
end
def self . update ( skip_subscription : false , skip_plugin : false )
notices = [ ]
if ! skip_subscription
2021-11-01 14:52:29 +01:00
subscription_messages = request ( :subscription_message )
2021-10-05 14:54:06 +02:00
2021-09-24 11:58:42 +02:00
if subscription_messages . present?
subscription_notices = convert_subscription_messages_to_notices ( subscription_messages [ :messages ] )
notices . push ( * subscription_notices )
end
end
2021-10-05 14:54:06 +02:00
if ! skip_plugin && request_plugin_status?
plugin_status = request ( :plugin_status )
2021-09-24 11:58:42 +02:00
2021-11-01 14:52:29 +01:00
if plugin_status . present? && plugin_status [ :status ] . present?
plugin_notice = convert_plugin_status_to_notice ( plugin_status )
2021-09-24 11:58:42 +02:00
notices . push ( plugin_notice ) if plugin_notice
end
end
2021-11-01 14:52:29 +01:00
if notices . any?
notices . each do | notice_data |
notice = new ( notice_data )
notice . retrieved_at = Time . now
notice . save
end
publish_notice_count
2021-09-24 11:58:42 +02:00
end
end
2021-11-01 14:52:29 +01:00
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
2021-09-24 11:58:42 +02:00
def self . convert_subscription_messages_to_notices ( messages )
2021-11-01 14:52:29 +01:00
messages . reduce ( [ ] ) do | result , message |
notice_id = generate_notice_id ( message [ :title ] , message [ :created_at ] )
unless exists? ( notice_id )
result . push (
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 ]
)
end
result
2021-09-24 11:58:42 +02:00
end
end
def self . convert_plugin_status_to_notice ( plugin_status )
notice = nil
if PLUGIN_STATUSES_TO_WARN . include? ( plugin_status [ :status ] )
2021-11-01 14:52:29 +01:00
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
2021-09-24 11:58:42 +02:00
else
2021-11-01 14:52:29 +01:00
expire_all ( types [ :warning ] , archetypes [ :plugin_status ] )
2021-09-24 11:58:42 +02:00
end
notice
end
2021-11-01 14:52:29 +01:00
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 )
2021-10-05 14:54:06 +02:00
if notices . any?
notice = notices . first
notice . updated_at = Time . now
notice . save
else
notice = new (
2021-11-01 14:52:29 +01:00
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 : Time . now ,
updated_at : Time . now
2021-10-05 14:54:06 +02:00
)
notice . save
end
2021-11-01 14:52:29 +01:00
publish_notice_count
2021-10-05 14:54:06 +02:00
end
def self . request_plugin_status?
CHECK_PLUGIN_STATUS_ON_BRANCH . include? ( Discourse . git_branch ) || Rails . env . test? || Rails . env . development?
end
2021-11-01 14:52:29 +01:00
def self . subscription_message_domain
( Rails . env . test? || Rails . env . development? ) ? LOCALHOST_DOMAIN : SUBSCRIPTION_MESSAGE_DOMAIN
2021-09-24 11:58:42 +02:00
end
2021-11-01 14:52:29 +01:00
def self . subscription_message_url
" http:// #{ subscription_message_domain } /subscription-server/messages.json "
2021-09-24 11:58:42 +02:00
end
def self . plugin_status_domain
2021-10-05 14:54:06 +02:00
return LOCALHOST_DOMAIN if ( Rails . env . test? || Rails . env . development? )
PLUGIN_STATUS_DOMAINS [ Discourse . git_branch ]
2021-09-24 11:58:42 +02:00
end
def self . plugin_status_url
" http:// #{ plugin_status_domain } /plugin-manager/status/discourse-custom-wizard "
end
2021-10-05 14:54:06 +02:00
2021-11-01 14:52:29 +01:00
def self . request ( archetype )
url = self . send ( " #{ archetype . to_s } _url " )
2021-09-24 11:58:42 +02:00
2021-11-01 14:52:29 +01:00
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
2021-10-05 14:54:06 +02:00
connection_error . expire!
2021-11-01 14:52:29 +01:00
expire_all ( types [ :connection_error ] , archetypes [ archetype . to_sym ] )
2021-10-05 14:54:06 +02:00
2021-09-24 11:58:42 +02:00
begin
data = JSON . parse ( response . body ) . deep_symbolize_keys
rescue JSON :: ParserError
return nil
end
2021-10-05 14:54:06 +02:00
2021-09-24 11:58:42 +02:00
data
else
2021-10-05 14:54:06 +02:00
connection_error . create!
2021-11-01 14:52:29 +01:00
notify_connection_errors ( archetype ) if connection_error . reached_limit?
2021-09-24 11:58:42 +02:00
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
2021-11-01 14:52:29 +01:00
def self . exists? ( id )
PluginStoreRow . where ( plugin_name : namespace , key : id ) . exists?
end
2021-09-24 11:58:42 +02:00
def self . store ( id , raw_notice )
PluginStore . set ( namespace , id , raw_notice )
end
2021-11-01 14:52:29 +01:00
def self . list_query ( type : nil , archetype : nil , title : nil , include_all : false , include_recently_expired : false , page : nil , visible : false )
2021-09-24 11:58:42 +02:00
query = PluginStoreRow . where ( plugin_name : namespace )
2021-11-01 14:52:29 +01:00
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 #{ include_recently_expired ? " OR (value::json->>'expired_at')::date > now()::date - 1 " : " " } " ) 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 " )
2021-09-24 11:58:42 +02:00
end
2021-11-01 14:52:29 +01:00
def self . list ( type : nil , archetype : nil , title : nil , include_all : false , include_recently_expired : false , page : 0 , visible : false )
list_query ( type : type , archetype : archetype , title : title , include_all : include_all , include_recently_expired : include_recently_expired , page : page , visible : visible )
2021-09-24 11:58:42 +02:00
. map { | r | self . new ( JSON . parse ( r . value ) . symbolize_keys ) }
end
2021-11-01 14:52:29 +01:00
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
2021-09-24 11:58:42 +02:00
end