Module: DiscourseUpdates

Defined in:
lib/discourse_updates.rb

Class Method Summary collapse

Class Method Details

.bump_last_viewed_feature_date(user_id, feature_date) ⇒ Object



219
220
221
# File 'lib/discourse_updates.rb', line 219

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

.check_versionObject



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/discourse_updates.rb', line 5

def check_version
  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!(
      latest_version: latest_version,
      critical_updates: critical_updates_available?,
      missing_versions_count: missing_versions_count,
    )
  end

  version_info = DiscourseVersionCheck.new(attrs)

  # replace -commit_count with +commit_count
  if version_info.installed_describe =~ /-(\d+)-/
    version_info.installed_describe =
      version_info.installed_describe.gsub(/-(\d+)-.*/, " +#{$1}")
  end

  if SiteSetting.version_checks?
    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
        )

    # Handle cases when version check data is old so we report something that makes sense
    if version_info.updated_at.nil? || last_installed_version != Discourse::VERSION::STRING || # never performed a version check # updated since the last version check
         is_stale_data
      Jobs.enqueue(:call_discourse_hub, all_sites: true)
      version_info.version_check_pending = true

      unless version_info.updated_at.nil?
        version_info.missing_versions_count = 0
        version_info.critical_updates = false
      end
    end

    version_info.stale_data =
      version_info.version_check_pending || (updated_at && updated_at < 48.hours.ago) ||
        is_stale_data
  end

  version_info
end

.clean_stateObject



223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/discourse_updates.rb', line 223

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

.critical_updates_available=(arg) ⇒ Object



90
91
92
# File 'lib/discourse_updates.rb', line 90

def critical_updates_available=(arg)
  Discourse.redis.set(critical_updates_available_key, arg)
end

.critical_updates_available?Boolean

Returns:

  • (Boolean)


86
87
88
# File 'lib/discourse_updates.rb', line 86

def critical_updates_available?
  (Discourse.redis.get(critical_updates_available_key) || false) == "true"
end

.current_versionObject



130
131
132
# File 'lib/discourse_updates.rb', line 130

def current_version
  last_installed_version || Discourse::VERSION::STRING
end

.get_last_viewed_feature_date(user_id) ⇒ Object



213
214
215
216
217
# File 'lib/discourse_updates.rb', line 213

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

.has_unseen_features?(user_id) ⇒ Boolean

Returns:

  • (Boolean)


182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/discourse_updates.rb', line 182

def has_unseen_features?(user_id)
  entries = new_features
  return false if entries.nil?

  last_seen = new_features_last_seen(user_id)

  if last_seen.present?
    entries.select! { |item| Time.zone.parse(item["created_at"]) > last_seen }
  end

  entries.size > 0
end

.last_installed_versionObject

last_installed_version is the installed version at the time of the last version check



62
63
64
# File 'lib/discourse_updates.rb', line 62

def last_installed_version
  Discourse.redis.get last_installed_version_key
end

.last_installed_version=(arg) ⇒ Object



66
67
68
# File 'lib/discourse_updates.rb', line 66

def last_installed_version=(arg)
  Discourse.redis.set(last_installed_version_key, arg)
end

.latest_versionObject



70
71
72
# File 'lib/discourse_updates.rb', line 70

def latest_version
  Discourse.redis.get latest_version_key
end

.latest_version=(arg) ⇒ Object



74
75
76
# File 'lib/discourse_updates.rb', line 74

def latest_version=(arg)
  Discourse.redis.set(latest_version_key, arg)
end

.mark_new_features_as_seen(user_id) ⇒ Object



201
202
203
204
205
206
207
208
209
210
211
# File 'lib/discourse_updates.rb', line 201

def mark_new_features_as_seen(user_id)
  entries =
    begin
      JSON.parse(Discourse.redis.get(new_features_key))
    rescue StandardError
      nil
    end
  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

.missing_versionsObject



125
126
127
128
# File 'lib/discourse_updates.rb', line 125

def missing_versions
  keys = Discourse.redis.lrange(missing_versions_list_key, 0, 4) # max of 5 versions
  keys.present? ? keys.map { |k| Discourse.redis.hgetall(k) } : []
end

.missing_versions=(versions) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/discourse_updates.rb', line 103

def missing_versions=(versions)
  # delete previous list from redis
  prev_keys = Discourse.redis.lrange(missing_versions_list_key, 0, 4)
  if prev_keys
    Discourse.redis.del prev_keys
    Discourse.redis.del(missing_versions_list_key)
  end

  if versions.present?
    # store the list in redis
    version_keys = []
    versions[0, 5].each do |v|
      key = "#{missing_versions_key_prefix}:#{v["version"]}"
      Discourse.redis.mapped_hmset key, v
      version_keys << key
    end
    Discourse.redis.rpush missing_versions_list_key, version_keys
  end

  versions || []
end

.missing_versions_countObject



78
79
80
# File 'lib/discourse_updates.rb', line 78

def missing_versions_count
  Discourse.redis.get(missing_versions_count_key).try(:to_i)
end

.missing_versions_count=(arg) ⇒ Object



82
83
84
# File 'lib/discourse_updates.rb', line 82

def missing_versions_count=(arg)
  Discourse.redis.set(missing_versions_count_key, arg)
end

.new_features(force_refresh: false) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/discourse_updates.rb', line 145

def new_features(force_refresh: false)
  update_new_features if force_refresh

  entries =
    begin
      JSON.parse(Discourse.redis.get(new_features_key))
    rescue StandardError
      nil
    end
  return nil if entries.nil?

  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

  entries.select! do |item|
    begin
      valid_version =
        item["discourse_version"].nil? ||
          Discourse.has_needed_version?(current_version, item["discourse_version"])

      valid_plugin_name =
        item["plugin_name"].blank? || Discourse.plugins_by_name[item["plugin_name"]].present?

      valid_version && valid_plugin_name
    rescue StandardError
      nil
    end
  end

  entries.sort_by { |item| Time.zone.parse(item["created_at"]).to_i }.reverse
end

.new_features_endpointObject



238
239
240
241
# File 'lib/discourse_updates.rb', line 238

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

.new_features_last_seen(user_id) ⇒ Object



195
196
197
198
199
# File 'lib/discourse_updates.rb', line 195

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

.new_features_payloadObject



134
135
136
137
138
# File 'lib/discourse_updates.rb', line 134

def new_features_payload
  response =
    Excon.new(new_features_endpoint).request(expects: [200], method: :Get, read_timeout: 5)
  response.body
end

.update_new_features(payload = nil) ⇒ Object



140
141
142
143
# File 'lib/discourse_updates.rb', line 140

def update_new_features(payload = nil)
  payload ||= new_features_payload
  Discourse.redis.set(new_features_key, payload)
end

.updated_atObject



94
95
96
97
# File 'lib/discourse_updates.rb', line 94

def updated_at
  t = Discourse.redis.get(updated_at_key)
  t ? Time.zone.parse(t) : nil
end

.updated_at=(time_with_zone) ⇒ Object



99
100
101
# File 'lib/discourse_updates.rb', line 99

def updated_at=(time_with_zone)
  Discourse.redis.set updated_at_key, time_with_zone.as_json
end