mirror of
https://github.com/mastodon/mastodon.git
synced 2026-07-28 15:57:26 -05:00
130 lines
4.5 KiB
Ruby
130 lines
4.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class SoftwareUpdateCheckService < BaseService
|
|
def call
|
|
clean_outdated_updates!
|
|
clean_outdated_deprecations!
|
|
return unless SoftwareUpdate.check_enabled?
|
|
|
|
json = fetch_update_notices
|
|
process_update_notices!(json&.fetch('updatesAvailable', nil))
|
|
process_deprecation_notice!(json&.fetch('currentVersion', nil))
|
|
end
|
|
|
|
private
|
|
|
|
def clean_outdated_updates!
|
|
SoftwareUpdate.find_each do |software_update|
|
|
software_update.delete if software_update.outdated?
|
|
rescue ArgumentError
|
|
software_update.delete
|
|
end
|
|
end
|
|
|
|
def clean_outdated_deprecations!
|
|
SoftwareDeprecation.clear_irrelevant_branches!
|
|
end
|
|
|
|
def fetch_update_notices
|
|
Request.new(:get, "#{api_url}?version=#{version}").add_headers('Accept' => 'application/json', 'User-Agent' => 'Mastodon update checker').perform do |res|
|
|
return JSON.parse(res.body_with_limit) if res.code == 200
|
|
end
|
|
rescue *Mastodon::HTTP_CONNECTION_ERRORS, JSON::ParserError
|
|
nil
|
|
end
|
|
|
|
def api_url
|
|
Rails.configuration.x.mastodon.software_update_url
|
|
end
|
|
|
|
def version
|
|
@version ||= Mastodon::Version.to_s.split('+')[0]
|
|
end
|
|
|
|
def process_update_notices!(update_notices)
|
|
return if update_notices.blank?
|
|
|
|
# Clear notices that are not listed by the update server anymore
|
|
SoftwareUpdate.where.not(version: update_notices.pluck('version')).delete_all
|
|
|
|
# Check if any of the notices is new, and issue notifications
|
|
known_versions = SoftwareUpdate.where(version: update_notices.pluck('version')).pluck(:version)
|
|
new_update_notices = update_notices.filter { |notice| known_versions.exclude?(notice['version']) }
|
|
return if new_update_notices.blank?
|
|
|
|
SoftwareUpdate.upsert_all(update_notices.map do |notice|
|
|
{ version: notice['version'], urgent: notice['urgent'], type: notice['type'], release_notes: notice['releaseNotes'], end_of_support: notice['endOfSupport']&.to_date }
|
|
end, unique_by: :version)
|
|
|
|
new_updates = SoftwareUpdate.where(version: new_update_notices.pluck('version')).to_a
|
|
|
|
notify_devops!(new_updates)
|
|
end
|
|
|
|
def process_deprecation_notice!(current_version)
|
|
return if current_version.blank? || current_version['endOfSupport'].blank?
|
|
|
|
deprecation_notice = SoftwareDeprecation
|
|
.create_with(warning_issued: :none, end_of_support: current_version['endOfSupport'].to_date)
|
|
.find_or_create_by(branch: SoftwareDeprecation.current_branch)
|
|
|
|
deprecation_notice.update(end_of_support: current_version['endOfSupport'].to_date)
|
|
|
|
notify_of_end_of_support!(deprecation_notice)
|
|
end
|
|
|
|
def should_notify_user?(user, urgent_version, patch_version)
|
|
case user.settings['notification_emails.software_updates']
|
|
when 'none'
|
|
false
|
|
when 'critical'
|
|
urgent_version
|
|
when 'patch'
|
|
urgent_version || patch_version
|
|
when 'all'
|
|
true
|
|
end
|
|
end
|
|
|
|
def notify_devops!(new_updates)
|
|
has_new_urgent_version = new_updates.any?(&:urgent?)
|
|
has_new_patch_version = new_updates.any?(&:patch_type?)
|
|
|
|
User.those_who_can(:view_devops).includes(:account).find_each do |user|
|
|
next unless should_notify_user?(user, has_new_urgent_version, has_new_patch_version)
|
|
|
|
if has_new_urgent_version
|
|
AdminMailer.with(recipient: user.account).new_critical_software_updates.deliver_later
|
|
else
|
|
AdminMailer.with(recipient: user.account).new_software_updates.deliver_later
|
|
end
|
|
end
|
|
end
|
|
|
|
def should_notify_about_end_of_support?(user)
|
|
user.settings['notification_emails.end_of_support']
|
|
end
|
|
|
|
def send_notification_for_end_of_support_warning!(deprecation_notice, warning_type)
|
|
return if deprecation_notice.warning_issued == warning_type
|
|
|
|
User.those_who_can(:view_devops).includes(:account).find_each do |user|
|
|
next unless should_notify_about_end_of_support?(user)
|
|
|
|
AdminMailer.with(recipient: user.account).public_send("end_of_support_#{warning_type}").deliver_later
|
|
end
|
|
|
|
deprecation_notice.update!(warning_issued: warning_type)
|
|
end
|
|
|
|
def notify_of_end_of_support!(deprecation_notice)
|
|
if deprecation_notice.end_of_support.past?
|
|
send_notification_for_end_of_support_warning!(deprecation_notice, 'out_of_support_warning')
|
|
elsif deprecation_notice.end_of_support < 2.weeks.from_now
|
|
send_notification_for_end_of_support_warning!(deprecation_notice, 'two_weeks_warning')
|
|
elsif deprecation_notice.end_of_support < 3.months.from_now
|
|
send_notification_for_end_of_support_warning!(deprecation_notice, 'three_months_warning')
|
|
end
|
|
end
|
|
end
|