discourse/app/models/admin_dashboard_data.rb

262 lines
7.8 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
class AdminDashboardData
2015-07-07 12:52:19 +08:00
include StatsCacheable
2019-04-01 20:35:09 +08:00
# kept for backward compatibility
GLOBAL_REPORTS ||= []
2019-04-01 18:39:49 +08:00
def initialize(opts = {})
@opts = opts
end
def self.fetch_stats
new.as_json
end
def get_json
{}
end
def as_json(_options = nil)
@json ||= get_json
end
def self.reports(source)
source.map { |type| Report.find(type).as_json }
end
def self.stats_cache_key
"dashboard-data-#{Report::SCHEMA_VERSION}"
end
def self.add_problem_check(*syms, &blk)
@problem_syms.push(*syms) if syms
@problem_blocks << blk if blk
end
class << self; attr_reader :problem_syms, :problem_blocks, :problem_messages; end
def problems
problems = []
AdminDashboardData.problem_syms.each do |sym|
problems << public_send(sym)
end
AdminDashboardData.problem_blocks.each do |blk|
problems << instance_exec(&blk)
end
AdminDashboardData.problem_messages.each do |i18n_key|
problems << AdminDashboardData.problem_message_check(i18n_key)
end
problems.compact!
if problems.empty?
self.class.clear_problems_started
else
self.class.set_problems_started
end
problems
end
def self.problems_started_key
2019-04-01 18:39:49 +08:00
'dash-problems-started-at'
end
def self.set_problems_started
existing_time = $redis.get(problems_started_key)
$redis.setex(problems_started_key, 14.days.to_i, existing_time || Time.zone.now.to_s)
end
def self.clear_problems_started
$redis.del problems_started_key
end
def self.problems_started_at
s = $redis.get(problems_started_key)
s ? Time.zone.parse(s) : nil
end
2015-09-02 04:32:35 +08:00
# used for testing
def self.reset_problem_checks
@problem_syms = []
@problem_blocks = []
@problem_messages = [
'dashboard.bad_favicon_url',
'dashboard.poll_pop3_timeout',
'dashboard.poll_pop3_auth_error',
'dashboard.deprecated_api_usage',
'dashboard.update_mail_receiver'
]
2015-09-02 04:32:35 +08:00
add_problem_check :rails_env_check, :host_names_check, :force_https_check,
:ram_check, :google_oauth2_config_check,
2015-09-02 04:32:35 +08:00
:facebook_config_check, :twitter_config_check,
FEATURE: Automatically generate optimized site metadata icons (#7372) This change automatically resizes icons for various purposes. Admins can now upload `logo` and `logo_small`, and everything else will be auto-generated. Specific icons can still be uploaded separately if required. ## Core - Adds an SiteIconManager module which manages automatic resizing and fallback - Icons are looked up in the OptimizedImage table at runtime, and then cached in Redis. If the resized version is missing for some reason, then most icons will fall back to the original files. Some icons (e.g. PWA Manifest) will return `nil` (because an incorrectly sized icon is worse than a missing icon). - `SiteSetting.site_large_icon_url` will return the optimized version, including any fallback. `SiteSetting.large_icon` continues to return the upload object. This means that (almost) no changes are required in core/plugins to support this new system. - Icons are resized whenever a relevant site setting is changed, and during post-deploy migrations ## Wizard - Allows `requiresRefresh` wizard steps to reload data via AJAX instead of a full page reload - Add placeholders to the **icons** step of the wizard, which automatically update from the "Square Logo" - Various copy updates to support the changes - Remove the "upload-time" resizing for `large_icon`. This is no longer required. ## Site Settings UX - Move logo/icon settings under a new "Branding" tab - Various copy changes to support the changes - Adds placeholder support to the `image-uploader` component - Automatically reloads site settings after saving. This allows setting placeholders to change based on changes to other settings - Upload site settings will be assigned a placeholder if SiteIconManager `responds_to?` an icon of the same name ## Dashboard Warnings - Remove PWA icon and PWA title warnings. Both are now handled automatically. ## Bonus - Updated the sketch logos to use @awesomerobot's new high-res designs
2019-05-01 21:44:45 +08:00
:github_config_check, :s3_config_check,
:image_magick_check, :failing_emails_check,
:subfolder_ends_in_slash_check,
:pop3_polling_configuration, :email_polling_errored_recently,
:out_of_date_themes, :unreachable_themes, :watched_words_check
2015-09-02 04:32:35 +08:00
add_problem_check do
sidekiq_check || queue_size_check
end
end
2015-09-02 04:32:35 +08:00
reset_problem_checks
def self.fetch_problems(opts = {})
AdminDashboardData.new(opts).problems
end
def self.problem_message_check(i18n_key)
$redis.get(problem_message_key(i18n_key)) ? I18n.t(i18n_key, base_path: Discourse.base_path) : nil
end
2017-07-28 09:20:09 +08:00
def self.add_problem_message(i18n_key, expire_seconds = nil)
if expire_seconds.to_i > 0
$redis.setex problem_message_key(i18n_key), expire_seconds.to_i, 1
else
$redis.set problem_message_key(i18n_key), 1
end
end
def self.clear_problem_message(i18n_key)
$redis.del problem_message_key(i18n_key)
end
def self.problem_message_key(i18n_key)
"admin-problem:#{i18n_key}"
end
def rails_env_check
I18n.t("dashboard.rails_env_warning", env: Rails.env) unless Rails.env.production?
end
def host_names_check
I18n.t("dashboard.host_names_warning") if ['localhost', 'production.localhost'].include?(Discourse.current_hostname)
end
def sidekiq_check
last_job_performed_at = Jobs.last_job_performed_at
I18n.t('dashboard.sidekiq_warning') if Jobs.queued > 0 && (last_job_performed_at.nil? || last_job_performed_at < 2.minutes.ago)
end
def queue_size_check
queue_size = Jobs.queued
I18n.t('dashboard.queue_size_warning', queue_size: queue_size) unless queue_size < 100_000
end
2013-03-23 03:47:25 +08:00
def ram_check
I18n.t('dashboard.memory_warning') if MemInfo.new.mem_total && MemInfo.new.mem_total < 950_000
2013-03-23 03:47:25 +08:00
end
def google_oauth2_config_check
if SiteSetting.enable_google_oauth2_logins && (SiteSetting.google_oauth2_client_id.blank? || SiteSetting.google_oauth2_client_secret.blank?)
I18n.t('dashboard.google_oauth2_config_warning', base_path: Discourse.base_path)
end
end
def facebook_config_check
if SiteSetting.enable_facebook_logins && (SiteSetting.facebook_app_id.blank? || SiteSetting.facebook_app_secret.blank?)
I18n.t('dashboard.facebook_config_warning', base_path: Discourse.base_path)
end
end
def twitter_config_check
if SiteSetting.enable_twitter_logins && (SiteSetting.twitter_consumer_key.blank? || SiteSetting.twitter_consumer_secret.blank?)
I18n.t('dashboard.twitter_config_warning', base_path: Discourse.base_path)
end
end
def github_config_check
if SiteSetting.enable_github_logins && (SiteSetting.github_client_id.blank? || SiteSetting.github_client_secret.blank?)
I18n.t('dashboard.github_config_warning', base_path: Discourse.base_path)
end
2013-06-20 04:11:11 +08:00
end
def s3_config_check
# if set via global setting it is validated during the `use_s3?` call
if !GlobalSetting.use_s3?
bad_keys = (SiteSetting.s3_access_key_id.blank? || SiteSetting.s3_secret_access_key.blank?) && !SiteSetting.s3_use_iam_profile
if SiteSetting.enable_s3_uploads && (bad_keys || SiteSetting.s3_upload_bucket.blank?)
return I18n.t('dashboard.s3_config_warning', base_path: Discourse.base_path)
end
if SiteSetting.backup_location == BackupLocationSiteSetting::S3 && (bad_keys || SiteSetting.s3_backup_bucket.blank?)
return I18n.t('dashboard.s3_backup_config_warning', base_path: Discourse.base_path)
end
end
nil
end
2013-06-20 04:36:56 +08:00
def image_magick_check
I18n.t('dashboard.image_magick_warning') if SiteSetting.create_thumbnails && !system("command -v convert >/dev/null;")
2013-06-20 04:36:56 +08:00
end
def failing_emails_check
num_failed_jobs = Jobs.num_email_retry_jobs
I18n.t('dashboard.failing_emails_warning', num_failed_jobs: num_failed_jobs, base_path: Discourse.base_path) if num_failed_jobs > 0
end
def subfolder_ends_in_slash_check
I18n.t('dashboard.subfolder_ends_in_slash') if Discourse.base_uri =~ /\/$/
end
def pop3_polling_configuration
POP3PollingEnabledSettingValidator.new.error_message if SiteSetting.pop3_polling_enabled
end
def email_polling_errored_recently
errors = Jobs::PollMailbox.errors_in_past_24_hours
I18n.t('dashboard.email_polling_errored_recently', count: errors, base_path: Discourse.base_path) if errors > 0
end
2016-05-30 23:11:17 +08:00
def missing_mailgun_api_key
return unless SiteSetting.reply_by_email_enabled
2019-04-01 18:39:49 +08:00
return unless ActionMailer::Base.smtp_settings[:address]['smtp.mailgun.org']
2016-05-30 23:11:17 +08:00
return unless SiteSetting.mailgun_api_key.blank?
I18n.t('dashboard.missing_mailgun_api_key')
end
def force_https_check
return unless @opts[:check_force_https]
I18n.t('dashboard.force_https_warning', base_path: Discourse.base_path) unless SiteSetting.force_https
end
def watched_words_check
WatchedWord.actions.keys.each do |action|
begin
WordWatcher.word_matcher_regexp(action, raise_errors: true)
rescue RegexpError => e
return I18n.t('dashboard.watched_word_regexp_error', base_path: Discourse.base_path, action: action)
end
end
nil
end
def out_of_date_themes
old_themes = RemoteTheme.out_of_date_themes
return unless old_themes.present?
2019-04-01 18:39:49 +08:00
themes_html_format(old_themes, 'dashboard.out_of_date_themes')
end
def unreachable_themes
themes = RemoteTheme.unreachable_themes
return unless themes.present?
2019-04-01 18:39:49 +08:00
themes_html_format(themes, 'dashboard.unreachable_themes')
end
private
def themes_html_format(themes, i18n_key)
html = themes.map do |name, id|
"<li><a href=\"/admin/customize/themes/#{id}\">#{CGI.escapeHTML(name)}</a></li>"
end.join("\n")
2019-04-01 18:39:49 +08:00
"#{I18n.t(i18n_key)}<ul>#{html}</ul>"
end
2013-06-20 04:11:11 +08:00
end