about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/admin/reports/actions_controller.rb4
-rw-r--r--app/javascript/styles/mastodon/admin.scss2
-rw-r--r--app/models/account_warning.rb13
-rw-r--r--app/models/admin/status_batch_action.rb34
-rw-r--r--app/models/status.rb4
-rw-r--r--app/services/approve_appeal_service.rb8
-rw-r--r--app/services/update_status_service.rb10
-rw-r--r--app/views/admin/reports/_actions.html.haml6
-rw-r--r--config/locales/en.yml16
9 files changed, 81 insertions, 16 deletions
diff --git a/app/controllers/admin/reports/actions_controller.rb b/app/controllers/admin/reports/actions_controller.rb
index 05a4fb63d..5cb5c744f 100644
--- a/app/controllers/admin/reports/actions_controller.rb
+++ b/app/controllers/admin/reports/actions_controller.rb
@@ -7,7 +7,7 @@ class Admin::Reports::ActionsController < Admin::BaseController
     authorize @report, :show?
 
     case action_from_button
-    when 'delete'
+    when 'delete', 'mark_as_sensitive'
       status_batch_action = Admin::StatusBatchAction.new(
         type: action_from_button,
         status_ids: @report.status_ids,
@@ -41,6 +41,8 @@ class Admin::Reports::ActionsController < Admin::BaseController
   def action_from_button
     if params[:delete]
       'delete'
+    elsif params[:mark_as_sensitive]
+      'mark_as_sensitive'
     elsif params[:silence]
       'silence'
     elsif params[:suspend]
diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss
index f49a354dc..52bc2086a 100644
--- a/app/javascript/styles/mastodon/admin.scss
+++ b/app/javascript/styles/mastodon/admin.scss
@@ -1504,6 +1504,8 @@ a.sparkline {
   word-wrap: break-word;
   font-weight: 400;
   color: $primary-text-color;
+  box-sizing: border-box;
+  min-height: 100%;
 
   p {
     margin-bottom: 20px;
diff --git a/app/models/account_warning.rb b/app/models/account_warning.rb
index 14d5ac388..6067b54b7 100644
--- a/app/models/account_warning.rb
+++ b/app/models/account_warning.rb
@@ -17,12 +17,13 @@
 
 class AccountWarning < ApplicationRecord
   enum action: {
-    none:            0,
-    disable:         1_000,
-    delete_statuses: 1_500,
-    sensitive:       2_000,
-    silence:         3_000,
-    suspend:         4_000,
+    none:                       0,
+    disable:                    1_000,
+    mark_statuses_as_sensitive: 1_250,
+    delete_statuses:            1_500,
+    sensitive:                  2_000,
+    silence:                    3_000,
+    suspend:                    4_000,
   }, _suffix: :action
 
   belongs_to :account, inverse_of: :account_warnings
diff --git a/app/models/admin/status_batch_action.rb b/app/models/admin/status_batch_action.rb
index 40f60f379..4d91b9805 100644
--- a/app/models/admin/status_batch_action.rb
+++ b/app/models/admin/status_batch_action.rb
@@ -30,6 +30,8 @@ class Admin::StatusBatchAction
     case type
     when 'delete'
       handle_delete!
+    when 'mark_as_sensitive'
+      handle_mark_as_sensitive!
     when 'report'
       handle_report!
     when 'remove_from_report'
@@ -65,6 +67,38 @@ class Admin::StatusBatchAction
     RemovalWorker.push_bulk(status_ids) { |status_id| [status_id, { 'preserve' => target_account.local?, 'immediate' => !target_account.local? }] }
   end
 
+  def handle_mark_as_sensitive!
+    # Can't use a transaction here because UpdateStatusService queues
+    # Sidekiq jobs
+    statuses.includes(:media_attachments, :preview_cards).find_each do |status|
+      next unless status.with_media? || status.with_preview_card?
+
+      authorize(status, :update?)
+
+      if target_account.local?
+        UpdateStatusService.new.call(status, current_account.id, sensitive: true)
+      else
+        status.update(sensitive: true)
+      end
+
+      log_action(:update, status)
+
+      if with_report?
+        report.resolve!(current_account)
+        log_action(:resolve, report)
+      end
+
+      @warning = target_account.strikes.create!(
+        action: :mark_statuses_as_sensitive,
+        account: current_account,
+        report: report,
+        status_ids: status_ids
+      )
+    end
+
+    UserMailer.warning(target_account.user, @warning).deliver_later! if warnable?
+  end
+
   def handle_report!
     @report = Report.new(report_params) unless with_report?
     @report.status_ids = (@report.status_ids + status_ids.map(&:to_i)).uniq
diff --git a/app/models/status.rb b/app/models/status.rb
index adb92ef91..60dde5045 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -231,6 +231,10 @@ class Status < ApplicationRecord
     media_attachments.any?
   end
 
+  def with_preview_card?
+    preview_cards.any?
+  end
+
   def non_sensitive_with_media?
     !sensitive? && with_media?
   end
diff --git a/app/services/approve_appeal_service.rb b/app/services/approve_appeal_service.rb
index f76bf8943..37a08b46e 100644
--- a/app/services/approve_appeal_service.rb
+++ b/app/services/approve_appeal_service.rb
@@ -27,6 +27,8 @@ class ApproveAppealService < BaseService
       undo_disable!
     when 'delete_statuses'
       undo_delete_statuses!
+    when 'mark_statuses_as_sensitive'
+      undo_mark_statuses_as_sensitive!
     when 'sensitive'
       undo_sensitive!
     when 'silence'
@@ -49,6 +51,12 @@ class ApproveAppealService < BaseService
     # Cannot be undone
   end
 
+  def undo_mark_statuses_as_sensitive!
+    @strike.statuses.includes(:media_attachments).each do |status|
+      UpdateStatusService.new.call(status, @current_account.id, sensitive: false) if status.with_media?
+    end
+  end
+
   def undo_sensitive!
     target_account.unsensitize!
   end
diff --git a/app/services/update_status_service.rb b/app/services/update_status_service.rb
index 238ef0755..93203bc49 100644
--- a/app/services/update_status_service.rb
+++ b/app/services/update_status_service.rb
@@ -22,8 +22,8 @@ class UpdateStatusService < BaseService
 
     Status.transaction do
       create_previous_edit!
-      update_media_attachments!
-      update_poll!
+      update_media_attachments! if @options.key?(:media_ids)
+      update_poll! if @options.key?(:poll)
       update_immediate_attributes!
       create_edit!
     end
@@ -91,9 +91,9 @@ class UpdateStatusService < BaseService
   end
 
   def update_immediate_attributes!
-    @status.text         = @options[:text].presence || @options.delete(:spoiler_text) || ''
-    @status.spoiler_text = @options[:spoiler_text] || ''
-    @status.sensitive    = @options[:sensitive] || @options[:spoiler_text].present?
+    @status.text         = @options[:text].presence || @options.delete(:spoiler_text) || '' if @options.key?(:text)
+    @status.spoiler_text = @options[:spoiler_text] || '' if @options.key?(:spoiler_text)
+    @status.sensitive    = @options[:sensitive] || @options[:spoiler_text].present? if @options.key?(:sensitive) || @options.key?(:spoiler_text)
     @status.language     = valid_locale_or_nil(@options[:language] || @status.language || @status.account.user&.preferred_posting_language || I18n.default_locale)
     @status.edited_at    = Time.now.utc
 
diff --git a/app/views/admin/reports/_actions.html.haml b/app/views/admin/reports/_actions.html.haml
index f3162b325..404d53a77 100644
--- a/app/views/admin/reports/_actions.html.haml
+++ b/app/views/admin/reports/_actions.html.haml
@@ -5,6 +5,12 @@
         = link_to t('admin.reports.mark_as_resolved'), resolve_admin_report_path(@report), method: :post, class: 'button'
       .report-actions__item__description
         = t('admin.reports.actions.resolve_description_html')
+    - if @statuses.any? { |status| status.with_media? || status.with_preview_card? }
+      .report-actions__item
+        .report-actions__item__button
+          = button_tag t('admin.reports.mark_as_sensitive'), name: :mark_as_sensitive, class: 'button'
+        .report-actions__item__description
+          = t('admin.reports.actions.mark_as_sensitive_description_html')
     .report-actions__item
       .report-actions__item__button
         = button_tag t('admin.reports.delete_and_resolve'), name: :delete, class: 'button button--destructive'
diff --git a/config/locales/en.yml b/config/locales/en.yml
index a68d87d10..35c2aa4bb 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -586,6 +586,7 @@ en:
       action_taken_by: Action taken by
       actions:
         delete_description_html: The reported posts will be deleted and a strike will be recorded to help you escalate on future infractions by the same account.
+        mark_as_sensitive_description_html: The media in the reported posts will be marked as sensitive and a strike will be recorded to help you escalate on future refractions by the same account.
         other_description_html: See more options for controlling the account's behaviour and customize communication to the reported account.
         resolve_description_html: No action will be taken against the reported account, no strike recorded, and the report will be closed.
         silence_description_html: The profile will be visible only to those who already follow it or manually look it up, severely limiting its reach. Can always be reverted.
@@ -606,6 +607,7 @@ en:
       forwarded: Forwarded
       forwarded_to: Forwarded to %{domain}
       mark_as_resolved: Mark as resolved
+      mark_as_sensitive: Mark as sensitive
       mark_as_unresolved: Mark as unresolved
       no_one_assigned: No one
       notes:
@@ -749,6 +751,7 @@ en:
       actions:
         delete_statuses: "%{name} deleted %{target}'s posts"
         disable: "%{name} froze %{target}'s account"
+        mark_statuses_as_sensitive: "%{name} marked %{target}'s posts as sensitive"
         none: "%{name} sent a warning to %{target}"
         sensitive: "%{name} marked %{target}'s account as sensitive"
         silence: "%{name} limited %{target}'s account"
@@ -831,6 +834,7 @@ en:
       actions:
         delete_statuses: to delete their posts
         disable: to freeze their account
+        mark_statuses_as_sensitive: to mark their posts as sensitive
         none: a warning
         sensitive: to mark their account as sensitive
         silence: to limit their account
@@ -1020,8 +1024,9 @@ en:
       title_actions:
         delete_statuses: Post removal
         disable: Freezing of account
+        mark_statuses_as_sensitive: Marking of posts as sensitive
         none: Warning
-        sensitive: Marking as sensitive of account
+        sensitive: Marking of account as sensitive
         silence: Limitation of account
         suspend: Suspension of account
       your_appeal_approved: Your appeal has been approved
@@ -1623,24 +1628,27 @@ en:
       explanation:
         delete_statuses: Some of your posts have been found to violate one or more community guidelines and have been subsequently removed by the moderators of %{instance}. Future violations may result in harsher punitive actions against your account.
         disable: You can no longer use your account, but your profile and other data remains intact. You can request a backup of your data, change account settings or delete your account.
+        mark_statuses_as_sensitive: Some of your posts have been marked as sensitive by the moderators of %{instance}. This means that people will need to tap the media in the posts before a preview is displayed. You can mark media as sensitive yourself when posting in the future.
         sensitive: From now on, all your uploaded media files will be marked as sensitive and hidden behind a click-through warning.
         silence: You can still use your account but only people who are already following you will see your posts on this server, and you may be excluded from various discovery features. However, others may still manually follow you.
         suspend: You can no longer use your account, and your profile and other data are no longer accessible. You can still login to request a backup of your data until the data is fully removed in about 30 days, but we will retain some basic data to prevent you from evading the suspension.
       get_in_touch: If you believe this is an error, you can reply to this e-mail to get in touch with the staff of %{instance}.
       reason: 'Reason:'
-      statuses: 'Posts that have been found in violation:'
+      statuses: 'Posts cited:'
       subject:
         delete_statuses: Your posts on %{acct} have been removed
         disable: Your account %{acct} has been frozen
+        mark_statuses_as_sensitive: Your posts on %{acct} have been marked as sensitive
         none: Warning for %{acct}
-        sensitive: Your media files on %{acct} will be marked as sensitive from now on
+        sensitive: Your posts on %{acct} will be marked as sensitive from now on
         silence: Your account %{acct} has been limited
         suspend: Your account %{acct} has been suspended
       title:
         delete_statuses: Posts removed
         disable: Account frozen
+        mark_statuses_as_sensitive: Posts marked as sensitive
         none: Warning
-        sensitive: Media hidden
+        sensitive: Account marked as sensitive
         silence: Account limited
         suspend: Account suspended
     welcome: