Merge commit 'ab85f59c30
' into kb_migration
This commit is contained in:
commit
c8a0050660
30 changed files with 321 additions and 63 deletions
27
app/controllers/backups_controller.rb
Normal file
27
app/controllers/backups_controller.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class BackupsController < ApplicationController
|
||||
include RoutingHelper
|
||||
|
||||
skip_before_action :require_functional!
|
||||
|
||||
before_action :authenticate_user!
|
||||
before_action :set_backup
|
||||
|
||||
def download
|
||||
case Paperclip::Attachment.default_options[:storage]
|
||||
when :s3
|
||||
redirect_to @backup.dump.expiring_url(10)
|
||||
when :fog
|
||||
redirect_to @backup.dump.expiring_url(Time.now.utc + 10)
|
||||
when :filesystem
|
||||
redirect_to full_asset_url(@backup.dump.url)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_backup
|
||||
@backup = current_user.backups.find(params[:id])
|
||||
end
|
||||
end
|
|
@ -52,7 +52,7 @@ module Settings
|
|||
end
|
||||
else
|
||||
flash[:error] = I18n.t('webauthn_credentials.create.error')
|
||||
status = :internal_server_error
|
||||
status = :unprocessable_entity
|
||||
end
|
||||
else
|
||||
flash[:error] = t('webauthn_credentials.create.error')
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
class Admin::SystemCheck
|
||||
ACTIVE_CHECKS = [
|
||||
Admin::SystemCheck::MediaPrivacyCheck,
|
||||
Admin::SystemCheck::DatabaseSchemaCheck,
|
||||
Admin::SystemCheck::SidekiqProcessCheck,
|
||||
Admin::SystemCheck::RulesCheck,
|
||||
|
|
|
@ -31,7 +31,7 @@ class Admin::SystemCheck::ElasticsearchCheck < Admin::SystemCheck::BaseCheck
|
|||
def running_version
|
||||
@running_version ||= begin
|
||||
Chewy.client.info['version']['number']
|
||||
rescue Faraday::ConnectionFailed
|
||||
rescue Faraday::ConnectionFailed, Elasticsearch::Transport::Transport::Error
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
|
105
app/lib/admin/system_check/media_privacy_check.rb
Normal file
105
app/lib/admin/system_check/media_privacy_check.rb
Normal file
|
@ -0,0 +1,105 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Admin::SystemCheck::MediaPrivacyCheck < Admin::SystemCheck::BaseCheck
|
||||
include RoutingHelper
|
||||
|
||||
def skip?
|
||||
!current_user.can?(:view_devops)
|
||||
end
|
||||
|
||||
def pass?
|
||||
check_media_uploads!
|
||||
@failure_message.nil?
|
||||
end
|
||||
|
||||
def message
|
||||
Admin::SystemCheck::Message.new(@failure_message, @failure_value, @failure_action, true)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_media_uploads!
|
||||
if Rails.configuration.x.use_s3
|
||||
check_media_listing_inaccessible_s3!
|
||||
else
|
||||
check_media_listing_inaccessible!
|
||||
end
|
||||
end
|
||||
|
||||
def check_media_listing_inaccessible!
|
||||
full_url = full_asset_url(media_attachment.file.url(:original, false))
|
||||
|
||||
# Check if we can list the uploaded file. If true, that's an error
|
||||
directory_url = Addressable::URI.parse(full_url)
|
||||
directory_url.query = nil
|
||||
filename = directory_url.path.gsub(%r{.*/}, '')
|
||||
directory_url.path = directory_url.path.gsub(%r{/[^/]+\Z}, '/')
|
||||
Request.new(:get, directory_url, allow_local: true).perform do |res|
|
||||
if res.truncated_body&.include?(filename)
|
||||
@failure_message = use_storage? ? :upload_check_privacy_error_object_storage : :upload_check_privacy_error
|
||||
@failure_action = 'https://docs.joinmastodon.org/admin/optional/object-storage/#FS'
|
||||
end
|
||||
end
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
|
||||
def check_media_listing_inaccessible_s3!
|
||||
urls_to_check = []
|
||||
paperclip_options = Paperclip::Attachment.default_options
|
||||
s3_protocol = paperclip_options[:s3_protocol]
|
||||
s3_host_alias = paperclip_options[:s3_host_alias]
|
||||
s3_host_name = paperclip_options[:s3_host_name]
|
||||
bucket_name = paperclip_options.dig(:s3_credentials, :bucket)
|
||||
|
||||
urls_to_check << "#{s3_protocol}://#{s3_host_alias}/" if s3_host_alias.present?
|
||||
urls_to_check << "#{s3_protocol}://#{s3_host_name}/#{bucket_name}/"
|
||||
urls_to_check.uniq.each do |full_url|
|
||||
check_s3_listing!(full_url)
|
||||
break if @failure_message.present?
|
||||
end
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
|
||||
def check_s3_listing!(full_url)
|
||||
bucket_url = Addressable::URI.parse(full_url)
|
||||
bucket_url.path = bucket_url.path.delete_suffix(media_attachment.file.path(:original))
|
||||
bucket_url.query = "max-keys=1&x-random=#{SecureRandom.hex(10)}"
|
||||
Request.new(:get, bucket_url, allow_local: true).perform do |res|
|
||||
if res.truncated_body&.include?('ListBucketResult')
|
||||
@failure_message = :upload_check_privacy_error_object_storage
|
||||
@failure_action = 'https://docs.joinmastodon.org/admin/optional/object-storage/#S3'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def media_attachment
|
||||
@media_attachment ||= begin
|
||||
attachment = Account.representative.media_attachments.first
|
||||
if attachment.present?
|
||||
attachment.touch # rubocop:disable Rails/SkipsModelValidations
|
||||
attachment
|
||||
else
|
||||
create_test_attachment!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_test_attachment!
|
||||
Tempfile.create(%w(test-upload .jpg), binmode: true) do |tmp_file|
|
||||
tmp_file.write(
|
||||
Base64.decode64(
|
||||
'/9j/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAYAAAA' \
|
||||
'AAAD/2wCEAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBA' \
|
||||
'QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE' \
|
||||
'BAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAf/AABEIAAEAAgMBEQACEQEDEQH/x' \
|
||||
'ABKAAEAAAAAAAAAAAAAAAAAAAALEAEAAAAAAAAAAAAAAAAAAAAAAQEAAAAAAAAAAAAAAAA' \
|
||||
'AAAAAEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwA/8H//2Q=='
|
||||
)
|
||||
)
|
||||
tmp_file.flush
|
||||
Account.representative.media_attachments.create!(file: tmp_file)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,11 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Admin::SystemCheck::Message
|
||||
attr_reader :key, :value, :action
|
||||
attr_reader :key, :value, :action, :critical
|
||||
|
||||
def initialize(key, value = nil, action = nil)
|
||||
@key = key
|
||||
@value = value
|
||||
@action = action
|
||||
def initialize(key, value = nil, action = nil, critical = false)
|
||||
@key = key
|
||||
@value = value
|
||||
@action = action
|
||||
@critical = critical
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,4 +20,10 @@ class ApplicationMailer < ActionMailer::Base
|
|||
headers['X-Auto-Response-Suppress'] = 'All'
|
||||
headers['Auto-Submitted'] = 'auto-generated'
|
||||
end
|
||||
|
||||
def set_autoreply_headers!
|
||||
headers['Precedence'] = 'list'
|
||||
headers['X-Auto-Response-Suppress'] = 'All'
|
||||
headers['Auto-Submitted'] = 'auto-generated'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,6 +18,6 @@
|
|||
class Backup < ApplicationRecord
|
||||
belongs_to :user, inverse_of: :backups
|
||||
|
||||
has_attached_file :dump
|
||||
validates_attachment_content_type :dump, content_type: /\Aapplication/
|
||||
has_attached_file :dump, s3_permissions: 'private'
|
||||
do_not_validate_attachment_file_type :dump
|
||||
end
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
- unless @system_checks.empty?
|
||||
.flash-message-stack
|
||||
- @system_checks.each do |message|
|
||||
.flash-message.warning
|
||||
.flash-message{ class: message.critical ? 'alert' : 'warning' }
|
||||
= t("admin.system_checks.#{message.key}.message_html", value: message.value ? content_tag(:strong, message.value) : nil)
|
||||
- if message.action
|
||||
= link_to t("admin.system_checks.#{message.key}.action"), message.action
|
||||
|
|
|
@ -54,15 +54,15 @@
|
|||
.strike-card__statuses-list__item
|
||||
- if (status = status_map[status_id.to_i])
|
||||
.one-liner
|
||||
= link_to short_account_status_url(@report.target_account, status_id), class: 'emojify' do
|
||||
= one_line_preview(status)
|
||||
.emojify= one_line_preview(status)
|
||||
|
||||
- status.ordered_media_attachments.each do |media_attachment|
|
||||
%abbr{ title: media_attachment.description }
|
||||
= fa_icon 'link'
|
||||
= media_attachment.file_file_name
|
||||
- status.ordered_media_attachments.each do |media_attachment|
|
||||
%abbr{ title: media_attachment.description }
|
||||
= fa_icon 'link'
|
||||
= media_attachment.file_file_name
|
||||
.strike-card__statuses-list__item__meta
|
||||
%time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
|
||||
= link_to ActivityPub::TagManager.instance.url_for(status), target: '_blank' do
|
||||
%time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
|
||||
- unless status.application.nil?
|
||||
·
|
||||
= status.application.name
|
||||
|
|
16
app/views/application/_sidebar.html.haml
Normal file
16
app/views/application/_sidebar.html.haml
Normal file
|
@ -0,0 +1,16 @@
|
|||
.hero-widget
|
||||
.hero-widget__img
|
||||
= image_tag @instance_presenter.thumbnail&.file&.url(:'@1x') || asset_pack_path('media/images/preview.png'), alt: @instance_presenter.title
|
||||
|
||||
.hero-widget__text
|
||||
%p= @instance_presenter.description.presence || t('about.about_mastodon_html')
|
||||
|
||||
- if Setting.trends && !(user_signed_in? && !current_user.setting_trends)
|
||||
- trends = Trends.tags.query.allowed.limit(3)
|
||||
|
||||
- unless trends.empty?
|
||||
.endorsements-widget.trends-widget
|
||||
%h4.emojify= t('footer.trending_now')
|
||||
|
||||
- trends.each do |tag|
|
||||
= react_component :hashtag, hashtag: ActiveModelSerializers::SerializableResource.new(tag, serializer: REST::TagSerializer, scope: current_user, scope_name: :current_user).as_json
|
|
@ -50,15 +50,15 @@
|
|||
.strike-card__statuses-list__item
|
||||
- if (status = status_map[status_id.to_i])
|
||||
.one-liner
|
||||
= link_to short_account_status_url(@strike.target_account, status_id), class: 'emojify' do
|
||||
= one_line_preview(status)
|
||||
.emojify= one_line_preview(status)
|
||||
|
||||
- status.ordered_media_attachments.each do |media_attachment|
|
||||
%abbr{ title: media_attachment.description }
|
||||
= fa_icon 'link'
|
||||
= media_attachment.file_file_name
|
||||
- status.ordered_media_attachments.each do |media_attachment|
|
||||
%abbr{ title: media_attachment.description }
|
||||
= fa_icon 'link'
|
||||
= media_attachment.file_file_name
|
||||
.strike-card__statuses-list__item__meta
|
||||
%time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
|
||||
= link_to ActivityPub::TagManager.instance.url_for(status), target: '_blank' do
|
||||
%time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
|
||||
- unless status.application.nil?
|
||||
·
|
||||
= status.application.name
|
||||
|
|
|
@ -64,6 +64,6 @@
|
|||
%td= l backup.created_at
|
||||
- if backup.processed?
|
||||
%td= number_to_human_size backup.dump_file_size
|
||||
%td= table_link_to 'download', t('exports.archive_takeout.download'), backup.dump.url
|
||||
%td= table_link_to 'download', t('exports.archive_takeout.download'), download_backup_url(backup)
|
||||
- else
|
||||
%td{ colspan: 2 }= t('exports.archive_takeout.in_progress')
|
||||
|
|
|
@ -55,5 +55,5 @@
|
|||
%tbody
|
||||
%tr
|
||||
%td.button-primary
|
||||
= link_to full_asset_url(@backup.dump.url) do
|
||||
= link_to download_backup_url(@backup) do
|
||||
%span= t 'exports.archive_takeout.download'
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
|
||||
<%= t 'user_mailer.backup_ready.explanation' %>
|
||||
|
||||
=> <%= full_asset_url(@backup.dump.url) %>
|
||||
=> <%= download_backup_url(@backup) %>
|
||||
|
|
|
@ -11,7 +11,7 @@ class ActivityPub::MigratedFollowDeliveryWorker < ActivityPub::DeliveryWorker
|
|||
def unfollow_old_account!(old_target_account_id)
|
||||
old_target_account = Account.find(old_target_account_id)
|
||||
UnfollowService.new.call(@source_account, old_target_account, skip_unmerge: true)
|
||||
rescue
|
||||
rescue StandardError
|
||||
true
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue