diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb index 24162ec63..4422825ee 100644 --- a/app/controllers/admin/dashboard_controller.rb +++ b/app/controllers/admin/dashboard_controller.rb @@ -3,13 +3,8 @@ require 'sidekiq/api' module Admin class DashboardController < BaseController - SIDEKIQ_QUEUES = %w(default push mailers pull scheduler).freeze - def index - missing_queues = Sidekiq::ProcessSet.new.reduce(SIDEKIQ_QUEUES) { |queues, process| queues - process['queues'] } - - flash.now[:alert] = I18n.t('admin.dashboard.misconfigured_sidekiq_alert', queues: missing_queues.join(', ')) unless missing_queues.empty? - + @system_checks = Admin::SystemCheck.perform @users_count = User.count @pending_users_count = User.pending.count @registrations_week = Redis.current.get("activity:accounts:local:#{current_week}") || 0 diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss index e0604303b..ef4a08c59 100644 --- a/app/javascript/styles/mastodon/forms.scss +++ b/app/javascript/styles/mastodon/forms.scss @@ -604,6 +604,12 @@ code { color: $valid-value-color; } + &.warning { + border: 1px solid rgba($gold-star, 0.5); + background: rgba($gold-star, 0.25); + color: $gold-star; + } + &.alert { border: 1px solid rgba($error-value-color, 0.5); background: rgba($error-value-color, 0.1); @@ -625,6 +631,19 @@ code { } } + &.warning a { + font-weight: 700; + color: inherit; + text-decoration: underline; + + &:hover, + &:focus, + &:active { + text-decoration: none; + color: inherit; + } + } + p { margin-bottom: 15px; } @@ -681,6 +700,29 @@ code { } } +.flash-message-stack { + margin-bottom: 30px; + + .flash-message { + border-radius: 0; + margin-bottom: 0; + border-top-width: 0; + + &:first-child { + border-radius: 4px 4px 0 0; + border-top-width: 1px; + } + + &:last-child { + border-radius: 0 0 4px 4px; + + &:first-child { + border-radius: 4px; + } + } + } +} + .form-footer { margin-top: 30px; text-align: center; diff --git a/app/lib/admin/system_check.rb b/app/lib/admin/system_check.rb new file mode 100644 index 000000000..afb20cb47 --- /dev/null +++ b/app/lib/admin/system_check.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class Admin::SystemCheck + ACTIVE_CHECKS = [ + Admin::SystemCheck::DatabaseSchemaCheck, + Admin::SystemCheck::SidekiqProcessCheck, + Admin::SystemCheck::RulesCheck, + ].freeze + + def self.perform + ACTIVE_CHECKS.each_with_object([]) do |klass, arr| + check = klass.new + + if check.pass? + arr + else + arr << check.message + end + end + end +end diff --git a/app/lib/admin/system_check/base_check.rb b/app/lib/admin/system_check/base_check.rb new file mode 100644 index 000000000..fcad8daca --- /dev/null +++ b/app/lib/admin/system_check/base_check.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class Admin::SystemCheck::BaseCheck + def pass? + raise NotImplementedError + end + + def message + raise NotImplementedError + end +end diff --git a/app/lib/admin/system_check/database_schema_check.rb b/app/lib/admin/system_check/database_schema_check.rb new file mode 100644 index 000000000..b93d1954e --- /dev/null +++ b/app/lib/admin/system_check/database_schema_check.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class Admin::SystemCheck::DatabaseSchemaCheck < Admin::SystemCheck::BaseCheck + def pass? + !ActiveRecord::Base.connection.migration_context.needs_migration? + end + + def message + Admin::SystemCheck::Message.new(:database_schema_check) + end +end diff --git a/app/lib/admin/system_check/message.rb b/app/lib/admin/system_check/message.rb new file mode 100644 index 000000000..bfcad3bf3 --- /dev/null +++ b/app/lib/admin/system_check/message.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class Admin::SystemCheck::Message + attr_reader :key, :value, :action + + def initialize(key, value = nil, action = nil) + @key = key + @value = value + @action = action + end +end diff --git a/app/lib/admin/system_check/rules_check.rb b/app/lib/admin/system_check/rules_check.rb new file mode 100644 index 000000000..1fbdf955d --- /dev/null +++ b/app/lib/admin/system_check/rules_check.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class Admin::SystemCheck::RulesCheck < Admin::SystemCheck::BaseCheck + include RoutingHelper + + def pass? + Rule.kept.exists? + end + + def message + Admin::SystemCheck::Message.new(:rules_check, nil, admin_rules_path) + end +end diff --git a/app/lib/admin/system_check/sidekiq_process_check.rb b/app/lib/admin/system_check/sidekiq_process_check.rb new file mode 100644 index 000000000..c44d86c44 --- /dev/null +++ b/app/lib/admin/system_check/sidekiq_process_check.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +class Admin::SystemCheck::SidekiqProcessCheck < Admin::SystemCheck::BaseCheck + SIDEKIQ_QUEUES = %w( + default + push + mailers + pull + scheduler + ingress + ).freeze + + def pass? + missing_queues.empty? + end + + def message + Admin::SystemCheck::Message.new(:sidekiq_process_check, missing_queues.join(', ')) + end + + private + + def missing_queues + @missing_queues ||= Sidekiq::ProcessSet.new.reduce(SIDEKIQ_QUEUES) { |queues, process| queues - process['queues'] } + end +end diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 2849f07aa..205538402 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -1,6 +1,14 @@ - content_for :page_title do = t('admin.dashboard.title') +- unless @system_checks.empty? + .flash-message-stack + - @system_checks.each do |message| + .flash-message.warning + = t("admin.system_checks.#{message.key}.message_html", message.value ? { value: content_tag(:strong, message.value) } : {}) + - if message.action + = link_to t("admin.system_checks.#{message.key}.action"), message.action + .dashboard__counters %div = link_to admin_accounts_url(local: 1, recent: 1) do diff --git a/config/locales/en.yml b/config/locales/en.yml index b907d3882..182a8e985 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -367,7 +367,6 @@ en: feature_timeline_preview: Timeline preview features: Features hidden_service: Federation with hidden services - misconfigured_sidekiq_alert: 'No Sidekiq process seems to be handling the following queues: %{queues}. Please review your Sidekiq configuration.' open_reports: open reports pending_tags: hashtags waiting for review pending_users: users waiting for review @@ -661,6 +660,14 @@ en: no_status_selected: No statuses were changed as none were selected title: Account statuses with_media: With media + system_checks: + database_schema_check: + message_html: There are pending database migrations. Please run them to ensure the application behaves as expected + rules_check: + action: Manage server rules + message_html: You haven't defined any server rules. + sidekiq_process_check: + message_html: No Sidekiq process running for the %{value} queue(s). Please review your Sidekiq configuration tags: accounts_today: Unique uses today accounts_week: Unique uses this week