2019-05-03 06:17:27 +08:00
# frozen_string_literal: true
2013-02-20 04:16:50 +08:00
module DiscourseUpdates
class << self
def check_version
2017-11-21 17:01:27 +08:00
attrs = {
installed_version : Discourse :: VERSION :: STRING ,
installed_sha : ( Discourse . git_version == " unknown " ? nil : Discourse . git_version ) ,
installed_describe : Discourse . full_version ,
git_branch : Discourse . git_branch ,
updated_at : updated_at ,
}
unless updated_at . nil?
attrs . merge! (
2013-07-03 23:06:07 +08:00
latest_version : latest_version ,
critical_updates : critical_updates_available? ,
2017-11-21 17:01:27 +08:00
missing_versions_count : missing_versions_count ,
2013-07-03 23:06:07 +08:00
)
end
2017-11-21 17:01:27 +08:00
version_info = DiscourseVersionCheck . new ( attrs )
2015-02-24 07:57:54 +08:00
# replace -commit_count with +commit_count
if version_info . installed_describe =~ / -( \ d+)- /
version_info . installed_describe =
version_info . installed_describe . gsub ( / -( \ d+)-.* / , " + #{ $1 } " )
end
2013-07-31 00:11:51 +08:00
if SiteSetting . version_checks?
2017-11-21 17:01:27 +08:00
is_stale_data =
(
version_info . missing_versions_count == 0 &&
version_info . latest_version != version_info . installed_version
) ||
(
version_info . missing_versions_count != 0 &&
version_info . latest_version == version_info . installed_version
)
2013-07-31 00:11:51 +08:00
# Handle cases when version check data is old so we report something that makes sense
2024-04-02 22:34:37 +08:00
if version_info . updated_at . nil? || last_installed_version != Discourse :: VERSION :: STRING || # never performed a version check # updated since the last version check
2017-11-21 17:01:27 +08:00
is_stale_data
2024-02-23 14:12:28 +08:00
Jobs . enqueue ( :call_discourse_hub , all_sites : true )
2013-11-05 01:51:01 +08:00
version_info . version_check_pending = true
2017-11-21 17:01:27 +08:00
2013-11-05 01:51:01 +08:00
unless version_info . updated_at . nil?
version_info . missing_versions_count = 0
version_info . critical_updates = false
end
2013-07-31 00:11:51 +08:00
end
2017-11-21 17:01:27 +08:00
version_info . stale_data =
version_info . version_check_pending || ( updated_at && updated_at < 48 . hours . ago ) ||
is_stale_data
2013-07-03 23:06:07 +08:00
end
version_info
2013-02-20 04:16:50 +08:00
end
2013-11-05 01:51:01 +08:00
# last_installed_version is the installed version at the time of the last version check
def last_installed_version
2019-12-03 17:05:53 +08:00
Discourse . redis . get last_installed_version_key
2013-11-05 01:51:01 +08:00
end
2021-10-27 16:39:28 +08:00
def last_installed_version = ( arg )
2021-11-09 14:20:09 +08:00
Discourse . redis . set ( last_installed_version_key , arg )
2021-10-27 16:39:28 +08:00
end
2013-02-20 04:16:50 +08:00
def latest_version
2019-12-03 17:05:53 +08:00
Discourse . redis . get latest_version_key
2013-02-20 04:16:50 +08:00
end
2021-10-27 16:39:28 +08:00
def latest_version = ( arg )
2021-11-09 14:20:09 +08:00
Discourse . redis . set ( latest_version_key , arg )
2021-10-27 16:39:28 +08:00
end
2013-03-06 07:14:51 +08:00
def missing_versions_count
2019-12-03 17:05:53 +08:00
Discourse . redis . get ( missing_versions_count_key ) . try ( :to_i )
2013-02-20 04:16:50 +08:00
end
2021-10-27 16:39:28 +08:00
def missing_versions_count = ( arg )
2021-10-29 09:03:11 +08:00
Discourse . redis . set ( missing_versions_count_key , arg )
2021-10-27 16:39:28 +08:00
end
2013-03-06 23:34:15 +08:00
def critical_updates_available?
2019-12-03 17:05:53 +08:00
( Discourse . redis . get ( critical_updates_available_key ) || false ) == " true "
2013-02-20 04:16:50 +08:00
end
2021-10-27 16:39:28 +08:00
def critical_updates_available = ( arg )
2021-10-29 09:03:11 +08:00
Discourse . redis . set ( critical_updates_available_key , arg )
2021-10-27 16:39:28 +08:00
end
2013-07-03 23:06:07 +08:00
def updated_at
2019-12-03 17:05:53 +08:00
t = Discourse . redis . get ( updated_at_key )
2013-07-03 23:06:07 +08:00
t ? Time . zone . parse ( t ) : nil
end
def updated_at = ( time_with_zone )
2019-12-03 17:05:53 +08:00
Discourse . redis . set updated_at_key , time_with_zone . as_json
2013-07-03 23:06:07 +08:00
end
2014-01-01 04:52:16 +08:00
def missing_versions = ( versions )
# delete previous list from redis
2019-12-03 17:05:53 +08:00
prev_keys = Discourse . redis . lrange ( missing_versions_list_key , 0 , 4 )
2014-01-01 04:52:16 +08:00
if prev_keys
2019-12-03 17:05:53 +08:00
Discourse . redis . del prev_keys
Discourse . redis . del ( missing_versions_list_key )
2014-01-01 04:52:16 +08:00
end
2014-01-08 03:31:54 +08:00
if versions . present?
# store the list in redis
version_keys = [ ]
versions [ 0 , 5 ] . each do | v |
key = " #{ missing_versions_key_prefix } : #{ v [ " version " ] } "
2019-12-03 17:05:53 +08:00
Discourse . redis . mapped_hmset key , v
2014-01-08 03:31:54 +08:00
version_keys << key
end
2019-12-03 17:05:53 +08:00
Discourse . redis . rpush missing_versions_list_key , version_keys
2014-01-01 04:52:16 +08:00
end
2014-01-08 03:31:54 +08:00
versions || [ ]
2014-01-01 04:52:16 +08:00
end
def missing_versions
2019-12-03 17:05:53 +08:00
keys = Discourse . redis . lrange ( missing_versions_list_key , 0 , 4 ) # max of 5 versions
keys . present? ? keys . map { | k | Discourse . redis . hgetall ( k ) } : [ ]
2014-01-01 04:52:16 +08:00
end
2021-04-22 00:40:27 +08:00
def current_version
last_installed_version || Discourse :: VERSION :: STRING
end
2021-02-12 21:52:59 +08:00
def new_features_payload
2024-11-27 07:40:55 +08:00
response =
Excon . new ( new_features_endpoint ) . request ( expects : [ 200 ] , method : :Get , read_timeout : 5 )
2021-02-12 23:49:10 +08:00
response . body
2021-02-12 21:52:59 +08:00
end
2021-02-12 23:49:10 +08:00
def update_new_features ( payload = nil )
payload || = new_features_payload
Discourse . redis . set ( new_features_key , payload )
2021-01-22 23:09:02 +08:00
end
2024-11-27 07:40:55 +08:00
def new_features ( force_refresh : false )
update_new_features if force_refresh
2021-01-22 23:09:02 +08:00
entries =
2023-01-09 20:10:19 +08:00
begin
2021-01-22 23:09:02 +08:00
JSON . parse ( Discourse . redis . get ( new_features_key ) )
rescue StandardError
nil
2023-01-09 20:10:19 +08:00
end
2021-01-22 23:09:02 +08:00
return nil if entries . nil?
2024-10-22 07:56:58 +08:00
entries . map! do | item |
next item if ! item [ " experiment_setting " ]
item [ " experiment_setting " ] = nil if ! SiteSetting . respond_to? ( item [ " experiment_setting " ] ) ||
SiteSetting . type_supervisor . get_type ( item [ " experiment_setting " ] . to_sym ) != :bool
item
end
2021-02-11 02:12:04 +08:00
entries . select! do | item |
2023-01-09 20:10:19 +08:00
begin
2024-10-22 07:56:58 +08:00
valid_version =
item [ " discourse_version " ] . nil? ||
Discourse . has_needed_version? ( current_version , item [ " discourse_version " ] )
valid_plugin_name =
2024-10-23 13:16:19 +08:00
item [ " plugin_name " ] . blank? || Discourse . plugins_by_name [ item [ " plugin_name " ] ] . present?
2024-10-22 07:56:58 +08:00
valid_version && valid_plugin_name
2021-04-22 00:40:27 +08:00
rescue StandardError
nil
2023-01-09 20:10:19 +08:00
end
2021-02-11 02:12:04 +08:00
end
2021-02-20 00:03:36 +08:00
entries . sort_by { | item | Time . zone . parse ( item [ " created_at " ] ) . to_i } . reverse
2021-02-11 02:12:04 +08:00
end
def has_unseen_features? ( user_id )
entries = new_features
return false if entries . nil?
2021-01-22 23:09:02 +08:00
last_seen = new_features_last_seen ( user_id )
if last_seen . present?
entries . select! { | item | Time . zone . parse ( item [ " created_at " ] ) > last_seen }
end
2021-02-11 02:12:04 +08:00
entries . size > 0
2021-01-22 23:09:02 +08:00
end
def new_features_last_seen ( user_id )
last_seen = Discourse . redis . get new_features_last_seen_key ( user_id )
return nil if last_seen . blank?
Time . zone . parse ( last_seen )
end
def mark_new_features_as_seen ( user_id )
entries =
2023-01-09 20:10:19 +08:00
begin
2021-01-22 23:09:02 +08:00
JSON . parse ( Discourse . redis . get ( new_features_key ) )
rescue StandardError
nil
2023-01-09 20:10:19 +08:00
end
2021-01-22 23:09:02 +08:00
return nil if entries . nil?
last_seen = entries . max_by { | x | x [ " created_at " ] }
Discourse . redis . set ( new_features_last_seen_key ( user_id ) , last_seen [ " created_at " ] )
end
2022-12-16 01:12:53 +08:00
def get_last_viewed_feature_date ( user_id )
date = Discourse . redis . hget ( last_viewed_feature_dates_for_users_key , user_id . to_s )
return if date . blank?
Time . zone . parse ( date )
end
def bump_last_viewed_feature_date ( user_id , feature_date )
Discourse . redis . hset ( last_viewed_feature_dates_for_users_key , user_id . to_s , feature_date )
end
2022-12-23 20:41:30 +08:00
def clean_state
Discourse . redis . del (
last_installed_version_key ,
latest_version_key ,
critical_updates_available_key ,
missing_versions_count_key ,
updated_at_key ,
missing_versions_list_key ,
new_features_key ,
last_viewed_feature_dates_for_users_key ,
* Discourse . redis . keys ( " #{ missing_versions_key_prefix } * " ) ,
* Discourse . redis . keys ( new_features_last_seen_key ( " * " ) ) ,
)
end
2023-11-09 11:50:21 +08:00
def new_features_endpoint
return " https://meta.discourse.org/new-features.json " if Rails . env . production?
ENV [ " DISCOURSE_NEW_FEATURES_ENDPOINT " ] || " http://localhost:4200/new-features.json "
end
2013-02-20 04:16:50 +08:00
private
2019-01-02 05:47:29 +08:00
def last_installed_version_key
" last_installed_version "
end
2013-11-05 01:51:01 +08:00
2019-01-02 05:47:29 +08:00
def latest_version_key
" discourse_latest_version "
end
2013-02-20 04:16:50 +08:00
2019-01-02 05:47:29 +08:00
def critical_updates_available_key
" critical_updates_available "
end
2013-03-06 07:14:51 +08:00
2019-01-02 05:47:29 +08:00
def missing_versions_count_key
" missing_versions_count "
end
2013-07-03 23:06:07 +08:00
2019-01-02 05:47:29 +08:00
def updated_at_key
" last_version_check_at "
end
2014-01-01 04:52:16 +08:00
2019-01-02 05:47:29 +08:00
def missing_versions_list_key
" missing_versions "
end
2014-01-01 04:52:16 +08:00
2019-01-02 05:47:29 +08:00
def missing_versions_key_prefix
" missing_version "
end
2021-01-22 23:09:02 +08:00
def new_features_key
" new_features "
end
def new_features_last_seen_key ( user_id )
" new_features_last_seen_user_ #{ user_id } "
end
2022-12-16 01:12:53 +08:00
def last_viewed_feature_dates_for_users_key
" last_viewed_feature_dates_for_users_hash "
end
2013-02-20 04:16:50 +08:00
end
2015-02-24 07:57:54 +08:00
end