Skip to content

Commit 5f70831

Browse files
Gargronhiyuki2578
authored andcommitted
Add soft delete for statuses for instant deletes through API (mastodon#11623)
* Add soft delete for statuses to allow them to appear instant * Allow reporting soft-deleted statuses and show them in the admin UI * Change index for getting an account's statuses
1 parent d1b0469 commit 5f70831

14 files changed

Lines changed: 42 additions & 8 deletions

File tree

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ gem 'omniauth-cas', '~> 1.1'
4343
gem 'omniauth-saml', '~> 1.10'
4444
gem 'omniauth', '~> 1.9'
4545

46+
gem 'discard', '~> 1.1'
4647
gem 'doorkeeper', '~> 5.1'
4748
gem 'fast_blank', '~> 1.0'
4849
gem 'fastimage'

Gemfile.lock

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ GEM
204204
devise (>= 4.0.0)
205205
rpam2 (~> 4.0)
206206
diff-lcs (1.3)
207+
discard (1.1.0)
208+
activerecord (>= 4.2, < 7)
207209
docile (1.3.2)
208210
domain_name (0.5.20180417)
209211
unf (>= 0.0.5, < 1.0.0)
@@ -692,6 +694,7 @@ DEPENDENCIES
692694
devise (~> 4.6)
693695
devise-two-factor (~> 3.1)
694696
devise_pam_authenticatable2 (~> 9.2)
697+
discard (~> 1.1)
695698
doorkeeper (~> 5.1)
696699
dotenv-rails (~> 2.7)
697700
fabrication (~> 2.20)

app/controllers/api/v1/reports_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def create
2121
private
2222

2323
def reported_status_ids
24-
reported_account.statuses.find(status_ids).pluck(:id)
24+
reported_account.statuses.with_discarded.find(status_ids).pluck(:id)
2525
end
2626

2727
def status_ids

app/controllers/api/v1/statuses/reblogs_controller.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ def destroy
1818
@reblogs_map = { @status.id => false }
1919

2020
authorize status_for_destroy, :unreblog?
21+
status_for_destroy.discard
2122
RemovalWorker.perform_async(status_for_destroy.id)
2223

2324
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_user&.account_id, reblogs_map: @reblogs_map)
@@ -30,7 +31,7 @@ def status_for_reblog
3031
end
3132

3233
def status_for_destroy
33-
current_user.account.statuses.where(reblog_of_id: params[:status_id]).first!
34+
@status_for_destroy ||= current_user.account.statuses.where(reblog_of_id: params[:status_id]).first!
3435
end
3536

3637
def reblog_params

app/controllers/api/v1/statuses_controller.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def destroy
5353
@status = Status.where(account_id: current_user.account).find(params[:id])
5454
authorize @status, :destroy?
5555

56+
@status.discard
5657
RemovalWorker.perform_async(@status.id, redraft: true)
5758

5859
render json: @status, serializer: REST::StatusSerializer, source_requested: true

app/models/form/status_batch.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def change_sensitive(sensitive)
3434

3535
def delete_statuses
3636
Status.where(id: status_ids).reorder(nil).find_each do |status|
37+
status.discard
3738
RemovalWorker.perform_async(status.id, redraft: false)
3839
Tombstone.find_or_create_by(uri: status.uri, account: status.account, by_moderator: true)
3940
log_action :destroy, status

app/models/report.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def object_type
4343
end
4444

4545
def statuses
46-
Status.where(id: status_ids).includes(:account, :media_attachments, :mentions)
46+
Status.with_discarded.where(id: status_ids).includes(:account, :media_attachments, :mentions)
4747
end
4848

4949
def media_attachments

app/models/status.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,19 @@
2222
# application_id :bigint(8)
2323
# in_reply_to_account_id :bigint(8)
2424
# poll_id :bigint(8)
25+
# deleted_at :datetime
2526
#
2627

2728
class Status < ApplicationRecord
2829
before_destroy :unlink_from_conversations
2930

31+
include Discard::Model
3032
include Paginable
3133
include Cacheable
3234
include StatusThreadingConcern
3335

36+
self.discard_column = :deleted_at
37+
3438
# If `override_timestamps` is set at creation time, Snowflake ID creation
3539
# will be based on current time instead of `created_at`
3640
attr_accessor :override_timestamps
@@ -72,7 +76,7 @@ class Status < ApplicationRecord
7276

7377
accepts_nested_attributes_for :poll
7478

75-
default_scope { recent }
79+
default_scope { recent.kept }
7680

7781
scope :recent, -> { reorder(id: :desc) }
7882
scope :remote, -> { where(local: false).where.not(uri: nil) }

app/views/admin/reports/_status.html.haml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@
1616
- video = status.proper.media_attachments.first
1717
= react_component :video, src: video.file.url(:original), preview: video.file.url(:small), sensitive: !current_account&.user&.show_all_media? && status.proper.sensitive? || current_account&.user&.hide_all_media?, width: 610, height: 343, inline: true, alt: video.description
1818
- else
19-
= react_component :media_gallery, height: 343, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, media: status.proper.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
19+
= react_component :media_gallery, height: 343, sensitive: !current_account&.user&.show_all_media? && status.proper.sensitive? || current_account&.user&.hide_all_media?, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, media: status.proper.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
2020

2121
.detailed-status__meta
2222
= link_to ActivityPub::TagManager.instance.url_for(status), class: 'detailed-status__datetime', target: stream_link_target, rel: 'noopener' do
2323
%time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
24+
- if status.discarded?
25+
·
26+
%span.negative-hint= t('admin.statuses.deleted')
2427
·
2528
- if status.reblog?
2629
= fa_icon('retweet fw')

app/workers/removal_worker.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ class RemovalWorker
44
include Sidekiq::Worker
55

66
def perform(status_id, options = {})
7-
RemoveStatusService.new.call(Status.find(status_id), **options.symbolize_keys)
7+
RemoveStatusService.new.call(Status.with_discarded.find(status_id), **options.symbolize_keys)
88
rescue ActiveRecord::RecordNotFound
99
true
1010
end

0 commit comments

Comments
 (0)