diff --git a/app/controllers/admin/instances_controller.rb b/app/controllers/admin/instances_controller.rb index e5a55de06d..a6997b62f7 100644 --- a/app/controllers/admin/instances_controller.rb +++ b/app/controllers/admin/instances_controller.rb @@ -49,7 +49,7 @@ module Admin private def set_instance - @instance = Instance.find(TagManager.instance.normalize_domain(params[:id]&.strip)) + @instance = Instance.find_or_initialize_by(domain: TagManager.instance.normalize_domain(params[:id]&.strip)) end def set_instances diff --git a/app/models/report.rb b/app/models/report.rb index eaf662d1e2..81ad721df1 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -142,6 +142,11 @@ class Report < ApplicationRecord target_type: 'Status', target_id: status_ids ).unscope(:order).arel, + + Admin::ActionLog.where( + target_type: 'AccountWarning', + target_id: AccountWarning.where(report_id: id).select(:id) + ).unscope(:order).arel, ].reduce { |union, query| Arel::Nodes::UnionAll.new(union, query) } Admin::ActionLog.from(Arel::Nodes::As.new(subquery, Admin::ActionLog.arel_table)) diff --git a/app/views/admin/instances/show.html.haml b/app/views/admin/instances/show.html.haml index 46b5c301b5..5f2664df76 100644 --- a/app/views/admin/instances/show.html.haml +++ b/app/views/admin/instances/show.html.haml @@ -7,27 +7,31 @@ = ' - ' = l(@time_period.last) - %p - = fa_icon 'info fw' - = t('admin.instances.totals_time_period_hint_html') + - if @instance.persisted? + %p + = fa_icon 'info fw' + = t('admin.instances.totals_time_period_hint_html') - .dashboard - .dashboard__item - = react_admin_component :counter, measure: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_accounts_measure'), href: admin_accounts_path(origin: 'remote', by_domain: @instance.domain) - .dashboard__item - = react_admin_component :counter, measure: 'instance_statuses', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_statuses_measure') - .dashboard__item - = react_admin_component :counter, measure: 'instance_media_attachments', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_media_attachments_measure') - .dashboard__item - = react_admin_component :counter, measure: 'instance_follows', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_follows_measure') - .dashboard__item - = react_admin_component :counter, measure: 'instance_followers', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_followers_measure') - .dashboard__item - = react_admin_component :counter, measure: 'instance_reports', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_reports_measure'), href: admin_reports_path(by_target_domain: @instance.domain) - .dashboard__item - = react_admin_component :dimension, dimension: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_accounts_dimension') - .dashboard__item - = react_admin_component :dimension, dimension: 'instance_languages', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_languages_dimension') + .dashboard + .dashboard__item + = react_admin_component :counter, measure: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_accounts_measure'), href: admin_accounts_path(origin: 'remote', by_domain: @instance.domain) + .dashboard__item + = react_admin_component :counter, measure: 'instance_statuses', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_statuses_measure') + .dashboard__item + = react_admin_component :counter, measure: 'instance_media_attachments', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_media_attachments_measure') + .dashboard__item + = react_admin_component :counter, measure: 'instance_follows', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_follows_measure') + .dashboard__item + = react_admin_component :counter, measure: 'instance_followers', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_followers_measure') + .dashboard__item + = react_admin_component :counter, measure: 'instance_reports', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_reports_measure'), href: admin_reports_path(by_target_domain: @instance.domain) + .dashboard__item + = react_admin_component :dimension, dimension: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_accounts_dimension') + .dashboard__item + = react_admin_component :dimension, dimension: 'instance_languages', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_languages_dimension') + - else + %p + = t('admin.instances.unknown_instance') %hr.spacer/ @@ -62,33 +66,34 @@ - else = link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @instance.domain), class: 'button' -%hr.spacer/ +- if @instance.persisted? + %hr.spacer/ -%h3= t('admin.instances.availability.title') + %h3= t('admin.instances.availability.title') -%p - = t('admin.instances.availability.description_html', count: DeliveryFailureTracker::FAILURE_DAYS_THRESHOLD) + %p + = t('admin.instances.availability.description_html', count: DeliveryFailureTracker::FAILURE_DAYS_THRESHOLD) -.availability-indicator - %ul.availability-indicator__graphic - - @instance.availability_over_days(14).each do |(date, failing)| - %li.availability-indicator__graphic__item{ class: failing ? 'negative' : 'neutral', title: l(date) } - .availability-indicator__hint - - if @instance.unavailable? - %span.negative-hint - = t('admin.instances.availability.failure_threshold_reached', date: l(@instance.unavailable_domain.created_at.to_date)) - = link_to t('admin.instances.delivery.restart'), restart_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } - - elsif @instance.exhausted_deliveries_days.empty? - %span.positive-hint - = t('admin.instances.availability.no_failures_recorded') - = link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } - - else - %span.negative-hint - = t('admin.instances.availability.failures_recorded', count: @instance.delivery_failure_tracker.days) - %span= link_to t('admin.instances.delivery.clear'), clear_delivery_errors_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } unless @instance.exhausted_deliveries_days.empty? - %span= link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } + .availability-indicator + %ul.availability-indicator__graphic + - @instance.availability_over_days(14).each do |(date, failing)| + %li.availability-indicator__graphic__item{ class: failing ? 'negative' : 'neutral', title: l(date) } + .availability-indicator__hint + - if @instance.unavailable? + %span.negative-hint + = t('admin.instances.availability.failure_threshold_reached', date: l(@instance.unavailable_domain.created_at.to_date)) + = link_to t('admin.instances.delivery.restart'), restart_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } + - elsif @instance.exhausted_deliveries_days.empty? + %span.positive-hint + = t('admin.instances.availability.no_failures_recorded') + = link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } + - else + %span.negative-hint + = t('admin.instances.availability.failures_recorded', count: @instance.delivery_failure_tracker.days) + %span= link_to t('admin.instances.delivery.clear'), clear_delivery_errors_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } unless @instance.exhausted_deliveries_days.empty? + %span= link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } -- if @instance.purgeable? - %p= t('admin.instances.purge_description_html') + - if @instance.purgeable? + %p= t('admin.instances.purge_description_html') - = link_to t('admin.instances.purge'), admin_instance_path(@instance), data: { confirm: t('admin.instances.confirm_purge'), method: :delete }, class: 'button button--destructive' + = link_to t('admin.instances.purge'), admin_instance_path(@instance), data: { confirm: t('admin.instances.confirm_purge'), method: :delete }, class: 'button button--destructive' diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 99c6ec023b..7130c574e3 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -4,6 +4,14 @@ # For further information see the following documentation # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy +def host_to_url(str) + return if str.blank? + + uri = Addressable::URI.parse("http#{Rails.configuration.x.use_https ? 's' : ''}://#{str}") + uri.path += '/' unless uri.path.blank? || uri.path.end_with?('/') + uri.to_s +end + def sso_host return unless ENV['ONE_CLICK_SSO_LOGIN'] == 'true' return unless ENV['OMNIAUTH_ONLY'] == 'true' @@ -27,8 +35,7 @@ unless Rails.env.development? data_hosts = [assets_host] if ENV['S3_ENABLED'] == 'true' || ENV['AZURE_ENABLED'] == 'true' - attachments_host = "https://#{ENV['S3_ALIAS_HOST'] || ENV['S3_CLOUDFRONT_HOST'] || ENV['AZURE_ALIAS_HOST'] || ENV['S3_HOSTNAME'] || "s3-#{ENV['S3_REGION'] || 'us-east-1'}.amazonaws.com"}" - attachments_host = "https://#{Addressable::URI.parse(attachments_host).host}" + attachments_host = host_to_url(ENV['S3_ALIAS_HOST'] || ENV['S3_CLOUDFRONT_HOST'] || ENV['AZURE_ALIAS_HOST'] || ENV['S3_HOSTNAME'] || "s3-#{ENV['S3_REGION'] || 'us-east-1'}.amazonaws.com") elsif ENV['SWIFT_ENABLED'] == 'true' attachments_host = ENV['SWIFT_OBJECT_URL'] attachments_host = "https://#{Addressable::URI.parse(attachments_host).host}" diff --git a/config/locales/en.yml b/config/locales/en.yml index 71b8f27aac..cbaec01a4e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -534,6 +534,7 @@ en: total_reported: Reports about them total_storage: Media attachments totals_time_period_hint_html: The totals displayed below include data for all time. + unknown_instance: There is currently no record of this domain on this server. invites: deactivate_all: Deactivate all filter: diff --git a/lib/tasks/mastodon.rake b/lib/tasks/mastodon.rake index f68d1cf1f8..22f29dbd04 100644 --- a/lib/tasks/mastodon.rake +++ b/lib/tasks/mastodon.rake @@ -17,6 +17,8 @@ namespace :mastodon do ENV.delete('SIDEKIQ_REDIS_URL') begin + errors = false + prompt.say('Your instance is identified by its domain name. Changing it afterward will break things.') env['LOCAL_DOMAIN'] = prompt.ask('Domain name:') do |q| q.required true @@ -95,7 +97,12 @@ namespace :mastodon do rescue => e prompt.error 'Database connection could not be established with this configuration, try again.' prompt.error e.message - break unless prompt.yes?('Try again?') + unless prompt.yes?('Try again?') + return prompt.warn 'Nothing saved. Bye!' unless prompt.yes?('Continue anyway?') + + errors = true + break + end end end @@ -135,7 +142,12 @@ namespace :mastodon do rescue => e prompt.error 'Redis connection could not be established with this configuration, try again.' prompt.error e.message - break unless prompt.yes?('Try again?') + unless prompt.yes?('Try again?') + return prompt.warn 'Nothing saved. Bye!' unless prompt.yes?('Continue anyway?') + + errors = true + break + end end end @@ -420,7 +432,12 @@ namespace :mastodon do rescue => e prompt.error 'E-mail could not be sent with this configuration, try again.' prompt.error e.message - break unless prompt.yes?('Try again?') + unless prompt.yes?('Try again?') + return prompt.warn 'Nothing saved. Bye!' unless prompt.yes?('Continue anyway?') + + errors = true + break + end end end @@ -466,6 +483,7 @@ namespace :mastodon do prompt.ok 'Done!' else prompt.error 'That failed! Perhaps your configuration is not right' + errors = true end end @@ -482,12 +500,17 @@ namespace :mastodon do prompt.say 'Done!' else prompt.error 'That failed! Maybe you need swap space?' + errors = true end end end prompt.say "\n" - prompt.ok 'All done! You can now power on the Mastodon server 🐘' + if errors + prompt.warn 'Your Mastodon server is set up, but there were some errors along the way, you may have to fix them.' + else + prompt.ok 'All done! You can now power on the Mastodon server 🐘' + end prompt.say "\n" if db_connection_works && prompt.yes?('Do you want to create an admin user straight away?')