Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - `Gemfile.lock`: Not a real conflict, upstream updated dependencies that were too close to glitch-soc-only ones in the file. - `app/controllers/oauth/authorized_applications_controller.rb`: Upstream changed the logic surrounding suspended accounts. Minor conflict due to glitch-soc's theming system. Ported upstream changes. - `app/controllers/settings/base_controller.rb`: Upstream refactored and changed the logic surrounding suspended accounts. Minor conflict due to glitch-soc's theming system. Ported upstream changes. - `app/controllers/settings/sessions_controller.rb`: Upstream refactored and changed the logic surrounding suspended accounts. Minor conflict due to glitch-soc's theming system. Ported upstream changes. - `app/models/user.rb`: Upstream refactored and changed the logic surrounding suspended accounts. Minor conflict due to glitch-soc not preventing moved accounts from logging in. Ported upstream changes while keeping the ability for moved accounts to log in. - `app/policies/status_policy.rb`: Upstream refactored and changed the logic surrounding suspended accounts. Minor conflict due to glitch-soc's local-only toots. Ported upstream changes. - `app/serializers/rest/account_serializer.rb`: Upstream refactored and changed the logic surrounding suspended accounts. Minor conflict due to glitch-soc's ability to hide followers count. Ported upstream changes. - `app/services/process_mentions_service.rb`: Upstream refactored and changed the logic surrounding suspended accounts. Minor conflict due to glitch-soc's local-only toots. Ported upstream changes. - `package.json`: Not a real conflict, upstream updated dependencies that were too close to glitch-soc-only ones in the file.
This commit is contained in:
@ -3,7 +3,7 @@
|
||||
class AfterUnallowDomainService < BaseService
|
||||
def call(domain)
|
||||
Account.where(domain: domain).find_each do |account|
|
||||
SuspendAccountService.new.call(account, reserve_username: false)
|
||||
DeleteAccountService.new.call(account, reserve_username: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -36,7 +36,7 @@ class BlockDomainService < BaseService
|
||||
def suspend_accounts!
|
||||
blocked_domain_accounts.without_suspended.in_batches.update_all(suspended_at: @domain_block.created_at)
|
||||
blocked_domain_accounts.where(suspended_at: @domain_block.created_at).reorder(nil).find_each do |account|
|
||||
SuspendAccountService.new.call(account, reserve_username: true, suspended_at: @domain_block.created_at)
|
||||
DeleteAccountService.new.call(account, reserve_username: true, suspended_at: @domain_block.created_at)
|
||||
end
|
||||
end
|
||||
|
||||
|
180
app/services/delete_account_service.rb
Normal file
180
app/services/delete_account_service.rb
Normal file
@ -0,0 +1,180 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class DeleteAccountService < BaseService
|
||||
include Payloadable
|
||||
|
||||
ASSOCIATIONS_ON_SUSPEND = %w(
|
||||
account_pins
|
||||
active_relationships
|
||||
block_relationships
|
||||
blocked_by_relationships
|
||||
conversation_mutes
|
||||
conversations
|
||||
custom_filters
|
||||
domain_blocks
|
||||
favourites
|
||||
follow_requests
|
||||
list_accounts
|
||||
mute_relationships
|
||||
muted_by_relationships
|
||||
notifications
|
||||
owned_lists
|
||||
passive_relationships
|
||||
report_notes
|
||||
scheduled_statuses
|
||||
status_pins
|
||||
).freeze
|
||||
|
||||
ASSOCIATIONS_ON_DESTROY = %w(
|
||||
reports
|
||||
targeted_moderation_notes
|
||||
targeted_reports
|
||||
).freeze
|
||||
|
||||
# Suspend or remove an account and remove as much of its data
|
||||
# as possible. If it's a local account and it has not been confirmed
|
||||
# or never been approved, then side effects are skipped and both
|
||||
# the user and account records are removed fully. Otherwise,
|
||||
# it is controlled by options.
|
||||
# @param [Account]
|
||||
# @param [Hash] options
|
||||
# @option [Boolean] :reserve_email Keep user record. Only applicable for local accounts
|
||||
# @option [Boolean] :reserve_username Keep account record
|
||||
# @option [Boolean] :skip_side_effects Side effects are ActivityPub and streaming API payloads
|
||||
# @option [Time] :suspended_at Only applicable when :reserve_username is true
|
||||
def call(account, **options)
|
||||
@account = account
|
||||
@options = { reserve_username: true, reserve_email: true }.merge(options)
|
||||
|
||||
if @account.local? && @account.user_unconfirmed_or_pending?
|
||||
@options[:reserve_email] = false
|
||||
@options[:reserve_username] = false
|
||||
@options[:skip_side_effects] = true
|
||||
end
|
||||
|
||||
reject_follows!
|
||||
purge_user!
|
||||
purge_profile!
|
||||
purge_content!
|
||||
fulfill_deletion_request!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def reject_follows!
|
||||
return if @account.local? || !@account.activitypub?
|
||||
|
||||
ActivityPub::DeliveryWorker.push_bulk(Follow.where(account: @account)) do |follow|
|
||||
[build_reject_json(follow), follow.target_account_id, follow.account.inbox_url]
|
||||
end
|
||||
end
|
||||
|
||||
def purge_user!
|
||||
return if !@account.local? || @account.user.nil?
|
||||
|
||||
if @options[:reserve_email]
|
||||
@account.user.disable!
|
||||
@account.user.invites.where(uses: 0).destroy_all
|
||||
else
|
||||
@account.user.destroy
|
||||
end
|
||||
end
|
||||
|
||||
def purge_content!
|
||||
distribute_delete_actor! if @account.local? && !@options[:skip_side_effects]
|
||||
|
||||
@account.statuses.reorder(nil).find_in_batches do |statuses|
|
||||
statuses.reject! { |status| reported_status_ids.include?(status.id) } if @options[:reserve_username]
|
||||
BatchedRemoveStatusService.new.call(statuses, skip_side_effects: @options[:skip_side_effects])
|
||||
end
|
||||
|
||||
@account.media_attachments.reorder(nil).find_each do |media_attachment|
|
||||
next if @options[:reserve_username] && reported_status_ids.include?(media_attachment.status_id)
|
||||
|
||||
media_attachment.destroy
|
||||
end
|
||||
|
||||
@account.polls.reorder(nil).find_each do |poll|
|
||||
next if @options[:reserve_username] && reported_status_ids.include?(poll.status_id)
|
||||
|
||||
poll.destroy
|
||||
end
|
||||
|
||||
associations_for_destruction.each do |association_name|
|
||||
destroy_all(@account.public_send(association_name))
|
||||
end
|
||||
|
||||
@account.destroy unless @options[:reserve_username]
|
||||
end
|
||||
|
||||
def purge_profile!
|
||||
# If the account is going to be destroyed
|
||||
# there is no point wasting time updating
|
||||
# its values first
|
||||
|
||||
return unless @options[:reserve_username]
|
||||
|
||||
@account.silenced_at = nil
|
||||
@account.suspended_at = @options[:suspended_at] || Time.now.utc
|
||||
@account.locked = false
|
||||
@account.memorial = false
|
||||
@account.discoverable = false
|
||||
@account.display_name = ''
|
||||
@account.note = ''
|
||||
@account.fields = []
|
||||
@account.statuses_count = 0
|
||||
@account.followers_count = 0
|
||||
@account.following_count = 0
|
||||
@account.moved_to_account = nil
|
||||
@account.trust_level = :untrusted
|
||||
@account.avatar.destroy
|
||||
@account.header.destroy
|
||||
@account.save!
|
||||
end
|
||||
|
||||
def fulfill_deletion_request!
|
||||
@account.deletion_request&.destroy
|
||||
end
|
||||
|
||||
def destroy_all(association)
|
||||
association.in_batches.destroy_all
|
||||
end
|
||||
|
||||
def distribute_delete_actor!
|
||||
ActivityPub::DeliveryWorker.push_bulk(delivery_inboxes) do |inbox_url|
|
||||
[delete_actor_json, @account.id, inbox_url]
|
||||
end
|
||||
|
||||
ActivityPub::LowPriorityDeliveryWorker.push_bulk(low_priority_delivery_inboxes) do |inbox_url|
|
||||
[delete_actor_json, @account.id, inbox_url]
|
||||
end
|
||||
end
|
||||
|
||||
def delete_actor_json
|
||||
@delete_actor_json ||= Oj.dump(serialize_payload(@account, ActivityPub::DeleteActorSerializer, signer: @account))
|
||||
end
|
||||
|
||||
def build_reject_json(follow)
|
||||
Oj.dump(serialize_payload(follow, ActivityPub::RejectFollowSerializer))
|
||||
end
|
||||
|
||||
def delivery_inboxes
|
||||
@delivery_inboxes ||= @account.followers.inboxes + Relay.enabled.pluck(:inbox_url)
|
||||
end
|
||||
|
||||
def low_priority_delivery_inboxes
|
||||
Account.inboxes - delivery_inboxes
|
||||
end
|
||||
|
||||
def reported_status_ids
|
||||
@reported_status_ids ||= Report.where(target_account: @account).unresolved.pluck(:status_ids).flatten.uniq
|
||||
end
|
||||
|
||||
def associations_for_destruction
|
||||
if @options[:reserve_username]
|
||||
ASSOCIATIONS_ON_SUSPEND
|
||||
else
|
||||
ASSOCIATIONS_ON_SUSPEND + ASSOCIATIONS_ON_DESTROY
|
||||
end
|
||||
end
|
||||
end
|
@ -29,7 +29,7 @@ class FavouriteService < BaseService
|
||||
status = favourite.status
|
||||
|
||||
if status.account.local?
|
||||
NotifyService.new.call(status.account, favourite)
|
||||
NotifyService.new.call(status.account, :favourite, favourite)
|
||||
elsif status.account.activitypub?
|
||||
ActivityPub::DeliveryWorker.perform_async(build_json(favourite), favourite.account_id, status.account.inbox_url)
|
||||
end
|
||||
|
@ -9,12 +9,13 @@ class FollowService < BaseService
|
||||
# @param [String, Account] uri User URI to follow in the form of username@domain (or account record)
|
||||
# @param [Hash] options
|
||||
# @option [Boolean] :reblogs Whether or not to show reblogs, defaults to true
|
||||
# @option [Boolean] :notify Whether to create notifications about new posts, defaults to false
|
||||
# @option [Boolean] :bypass_locked
|
||||
# @option [Boolean] :with_rate_limit
|
||||
def call(source_account, target_account, options = {})
|
||||
@source_account = source_account
|
||||
@target_account = ResolveAccountService.new.call(target_account, skip_webfinger: true)
|
||||
@options = { reblogs: true, bypass_locked: false, with_rate_limit: false }.merge(options)
|
||||
@options = { bypass_locked: false, with_rate_limit: false }.merge(options)
|
||||
|
||||
raise ActiveRecord::RecordNotFound if following_not_possible?
|
||||
raise Mastodon::NotPermittedError if following_not_allowed?
|
||||
@ -45,18 +46,18 @@ class FollowService < BaseService
|
||||
end
|
||||
|
||||
def change_follow_options!
|
||||
@source_account.follow!(@target_account, reblogs: @options[:reblogs])
|
||||
@source_account.follow!(@target_account, reblogs: @options[:reblogs], notify: @options[:notify])
|
||||
end
|
||||
|
||||
def change_follow_request_options!
|
||||
@source_account.request_follow!(@target_account, reblogs: @options[:reblogs])
|
||||
@source_account.request_follow!(@target_account, reblogs: @options[:reblogs], notify: @options[:notify])
|
||||
end
|
||||
|
||||
def request_follow!
|
||||
follow_request = @source_account.request_follow!(@target_account, reblogs: @options[:reblogs], rate_limit: @options[:with_rate_limit])
|
||||
follow_request = @source_account.request_follow!(@target_account, reblogs: @options[:reblogs], notify: @options[:notify], rate_limit: @options[:with_rate_limit])
|
||||
|
||||
if @target_account.local?
|
||||
LocalNotificationWorker.perform_async(@target_account.id, follow_request.id, follow_request.class.name)
|
||||
LocalNotificationWorker.perform_async(@target_account.id, follow_request.id, follow_request.class.name, :follow_request)
|
||||
elsif @target_account.activitypub?
|
||||
ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), @source_account.id, @target_account.inbox_url)
|
||||
end
|
||||
@ -65,9 +66,9 @@ class FollowService < BaseService
|
||||
end
|
||||
|
||||
def direct_follow!
|
||||
follow = @source_account.follow!(@target_account, reblogs: @options[:reblogs], rate_limit: @options[:with_rate_limit])
|
||||
follow = @source_account.follow!(@target_account, reblogs: @options[:reblogs], notify: @options[:notify], rate_limit: @options[:with_rate_limit])
|
||||
|
||||
LocalNotificationWorker.perform_async(@target_account.id, follow.id, follow.class.name)
|
||||
LocalNotificationWorker.perform_async(@target_account.id, follow.id, follow.class.name, :follow)
|
||||
MergeWorker.perform_async(@target_account.id, @source_account.id)
|
||||
|
||||
follow
|
||||
|
@ -25,7 +25,7 @@ class ImportService < BaseService
|
||||
|
||||
def import_follows!
|
||||
parse_import_data!(['Account address'])
|
||||
import_relationships!('follow', 'unfollow', @account.following, follow_limit, reblogs: 'Show boosts')
|
||||
import_relationships!('follow', 'unfollow', @account.following, follow_limit, reblogs: { header: 'Show boosts', default: true })
|
||||
end
|
||||
|
||||
def import_blocks!
|
||||
@ -35,7 +35,7 @@ class ImportService < BaseService
|
||||
|
||||
def import_mutes!
|
||||
parse_import_data!(['Account address'])
|
||||
import_relationships!('mute', 'unmute', @account.muting, ROWS_PROCESSING_LIMIT, notifications: 'Hide notifications')
|
||||
import_relationships!('mute', 'unmute', @account.muting, ROWS_PROCESSING_LIMIT, notifications: { header: 'Hide notifications', default: true })
|
||||
end
|
||||
|
||||
def import_domain_blocks!
|
||||
@ -65,7 +65,7 @@ class ImportService < BaseService
|
||||
|
||||
def import_relationships!(action, undo_action, overwrite_scope, limit, extra_fields = {})
|
||||
local_domain_suffix = "@#{Rails.configuration.x.local_domain}"
|
||||
items = @data.take(limit).map { |row| [row['Account address']&.strip&.delete_suffix(local_domain_suffix), Hash[extra_fields.map { |key, header| [key, row[header]&.strip] }]] }.reject { |(id, _)| id.blank? }
|
||||
items = @data.take(limit).map { |row| [row['Account address']&.strip&.delete_suffix(local_domain_suffix), Hash[extra_fields.map { |key, field_settings| [key, row[field_settings[:header]]&.strip || field_settings[:default]] }]] }.reject { |(id, _)| id.blank? }
|
||||
|
||||
if @import.overwrite?
|
||||
presence_hash = items.each_with_object({}) { |(id, extra), mapping| mapping[id] = [true, extra] }
|
||||
|
@ -1,10 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class NotifyService < BaseService
|
||||
def call(recipient, activity)
|
||||
def call(recipient, type, activity)
|
||||
@recipient = recipient
|
||||
@activity = activity
|
||||
@notification = Notification.new(account: @recipient, activity: @activity)
|
||||
@notification = Notification.new(account: @recipient, type: type, activity: @activity)
|
||||
|
||||
return if recipient.user.nil? || blocked?
|
||||
|
||||
@ -22,6 +22,10 @@ class NotifyService < BaseService
|
||||
FeedManager.instance.filter?(:mentions, @notification.mention.status, @recipient)
|
||||
end
|
||||
|
||||
def blocked_status?
|
||||
false
|
||||
end
|
||||
|
||||
def blocked_favourite?
|
||||
false
|
||||
end
|
||||
|
@ -58,7 +58,7 @@ class ProcessMentionsService < BaseService
|
||||
mentioned_account = mention.account
|
||||
|
||||
if mentioned_account.local?
|
||||
LocalNotificationWorker.perform_async(mentioned_account.id, mention.id, mention.class.name)
|
||||
LocalNotificationWorker.perform_async(mentioned_account.id, mention.id, mention.class.name, :mention)
|
||||
elsif mentioned_account.activitypub? && !@status.local_only?
|
||||
ActivityPub::DeliveryWorker.perform_async(activitypub_json, mention.status.account_id, mentioned_account.inbox_url)
|
||||
end
|
||||
|
@ -45,7 +45,7 @@ class ReblogService < BaseService
|
||||
reblogged_status = reblog.reblog
|
||||
|
||||
if reblogged_status.account.local?
|
||||
LocalNotificationWorker.perform_async(reblogged_status.account_id, reblog.id, reblog.class.name)
|
||||
LocalNotificationWorker.perform_async(reblogged_status.account_id, reblog.id, reblog.class.name, :reblog)
|
||||
elsif reblogged_status.account.activitypub? && !reblogged_status.account.following?(reblog.account)
|
||||
ActivityPub::DeliveryWorker.perform_async(build_json(reblog), reblog.account_id, reblogged_status.account.inbox_url)
|
||||
end
|
||||
|
@ -1,175 +1,52 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class SuspendAccountService < BaseService
|
||||
include Payloadable
|
||||
|
||||
ASSOCIATIONS_ON_SUSPEND = %w(
|
||||
account_pins
|
||||
active_relationships
|
||||
block_relationships
|
||||
blocked_by_relationships
|
||||
conversation_mutes
|
||||
conversations
|
||||
custom_filters
|
||||
domain_blocks
|
||||
favourites
|
||||
follow_requests
|
||||
list_accounts
|
||||
mute_relationships
|
||||
muted_by_relationships
|
||||
notifications
|
||||
owned_lists
|
||||
passive_relationships
|
||||
report_notes
|
||||
scheduled_statuses
|
||||
status_pins
|
||||
).freeze
|
||||
|
||||
ASSOCIATIONS_ON_DESTROY = %w(
|
||||
reports
|
||||
targeted_moderation_notes
|
||||
targeted_reports
|
||||
).freeze
|
||||
|
||||
# Suspend or remove an account and remove as much of its data
|
||||
# as possible. If it's a local account and it has not been confirmed
|
||||
# or never been approved, then side effects are skipped and both
|
||||
# the user and account records are removed fully. Otherwise,
|
||||
# it is controlled by options.
|
||||
# @param [Account]
|
||||
# @param [Hash] options
|
||||
# @option [Boolean] :reserve_email Keep user record. Only applicable for local accounts
|
||||
# @option [Boolean] :reserve_username Keep account record
|
||||
# @option [Boolean] :skip_side_effects Side effects are ActivityPub and streaming API payloads
|
||||
# @option [Time] :suspended_at Only applicable when :reserve_username is true
|
||||
def call(account, **options)
|
||||
def call(account)
|
||||
@account = account
|
||||
@options = { reserve_username: true, reserve_email: true }.merge(options)
|
||||
|
||||
if @account.local? && @account.user_unconfirmed_or_pending?
|
||||
@options[:reserve_email] = false
|
||||
@options[:reserve_username] = false
|
||||
@options[:skip_side_effects] = true
|
||||
end
|
||||
|
||||
reject_follows!
|
||||
purge_user!
|
||||
purge_profile!
|
||||
purge_content!
|
||||
suspend!
|
||||
unmerge_from_home_timelines!
|
||||
unmerge_from_list_timelines!
|
||||
privatize_media_attachments!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def reject_follows!
|
||||
return if @account.local? || !@account.activitypub?
|
||||
def suspend!
|
||||
@account.suspend! unless @account.suspended?
|
||||
end
|
||||
|
||||
ActivityPub::DeliveryWorker.push_bulk(Follow.where(account: @account)) do |follow|
|
||||
[build_reject_json(follow), follow.target_account_id, follow.account.inbox_url]
|
||||
def unmerge_from_home_timelines!
|
||||
@account.followers_for_local_distribution.find_each do |follower|
|
||||
FeedManager.instance.unmerge_from_timeline(@account, follower)
|
||||
end
|
||||
end
|
||||
|
||||
def purge_user!
|
||||
return if !@account.local? || @account.user.nil?
|
||||
|
||||
if @options[:reserve_email]
|
||||
@account.user.disable!
|
||||
@account.user.invites.where(uses: 0).destroy_all
|
||||
else
|
||||
@account.user.destroy
|
||||
def unmerge_from_list_timelines!
|
||||
@account.lists_for_local_distribution.find_each do |list|
|
||||
FeedManager.instance.unmerge_from_list(@account, list)
|
||||
end
|
||||
end
|
||||
|
||||
def purge_content!
|
||||
distribute_delete_actor! if @account.local? && !@options[:skip_side_effects]
|
||||
def privatize_media_attachments!
|
||||
attachment_names = MediaAttachment.attachment_definitions.keys
|
||||
|
||||
@account.statuses.reorder(nil).find_in_batches do |statuses|
|
||||
statuses.reject! { |status| reported_status_ids.include?(status.id) } if @options[:reserve_username]
|
||||
BatchedRemoveStatusService.new.call(statuses, skip_side_effects: @options[:skip_side_effects])
|
||||
end
|
||||
@account.media_attachments.find_each do |media_attachment|
|
||||
attachment_names.each do |attachment_name|
|
||||
attachment = media_attachment.public_send(attachment_name)
|
||||
styles = [:original] | attachment.styles.keys
|
||||
|
||||
@account.media_attachments.reorder(nil).find_each do |media_attachment|
|
||||
next if @options[:reserve_username] && reported_status_ids.include?(media_attachment.status_id)
|
||||
|
||||
media_attachment.destroy
|
||||
end
|
||||
|
||||
@account.polls.reorder(nil).find_each do |poll|
|
||||
next if @options[:reserve_username] && reported_status_ids.include?(poll.status_id)
|
||||
|
||||
poll.destroy
|
||||
end
|
||||
|
||||
associations_for_destruction.each do |association_name|
|
||||
destroy_all(@account.public_send(association_name))
|
||||
end
|
||||
|
||||
@account.destroy unless @options[:reserve_username]
|
||||
end
|
||||
|
||||
def purge_profile!
|
||||
# If the account is going to be destroyed
|
||||
# there is no point wasting time updating
|
||||
# its values first
|
||||
|
||||
return unless @options[:reserve_username]
|
||||
|
||||
@account.silenced_at = nil
|
||||
@account.suspended_at = @options[:suspended_at] || Time.now.utc
|
||||
@account.locked = false
|
||||
@account.memorial = false
|
||||
@account.discoverable = false
|
||||
@account.display_name = ''
|
||||
@account.note = ''
|
||||
@account.fields = []
|
||||
@account.statuses_count = 0
|
||||
@account.followers_count = 0
|
||||
@account.following_count = 0
|
||||
@account.moved_to_account = nil
|
||||
@account.trust_level = :untrusted
|
||||
@account.avatar.destroy
|
||||
@account.header.destroy
|
||||
@account.save!
|
||||
end
|
||||
|
||||
def destroy_all(association)
|
||||
association.in_batches.destroy_all
|
||||
end
|
||||
|
||||
def distribute_delete_actor!
|
||||
ActivityPub::DeliveryWorker.push_bulk(delivery_inboxes) do |inbox_url|
|
||||
[delete_actor_json, @account.id, inbox_url]
|
||||
end
|
||||
|
||||
ActivityPub::LowPriorityDeliveryWorker.push_bulk(low_priority_delivery_inboxes) do |inbox_url|
|
||||
[delete_actor_json, @account.id, inbox_url]
|
||||
end
|
||||
end
|
||||
|
||||
def delete_actor_json
|
||||
@delete_actor_json ||= Oj.dump(serialize_payload(@account, ActivityPub::DeleteActorSerializer, signer: @account))
|
||||
end
|
||||
|
||||
def build_reject_json(follow)
|
||||
Oj.dump(serialize_payload(follow, ActivityPub::RejectFollowSerializer))
|
||||
end
|
||||
|
||||
def delivery_inboxes
|
||||
@delivery_inboxes ||= @account.followers.inboxes + Relay.enabled.pluck(:inbox_url)
|
||||
end
|
||||
|
||||
def low_priority_delivery_inboxes
|
||||
Account.inboxes - delivery_inboxes
|
||||
end
|
||||
|
||||
def reported_status_ids
|
||||
@reported_status_ids ||= Report.where(target_account: @account).unresolved.pluck(:status_ids).flatten.uniq
|
||||
end
|
||||
|
||||
def associations_for_destruction
|
||||
if @options[:reserve_username]
|
||||
ASSOCIATIONS_ON_SUSPEND
|
||||
else
|
||||
ASSOCIATIONS_ON_SUSPEND + ASSOCIATIONS_ON_DESTROY
|
||||
styles.each do |style|
|
||||
case Paperclip::Attachment.default_options[:storage]
|
||||
when :s3
|
||||
attachment.s3_object(style).acl.put(:private)
|
||||
when :fog
|
||||
# Not supported
|
||||
when :filesystem
|
||||
FileUtils.chmod(0o600 & ~File.umask, attachment.path(style))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
52
app/services/unsuspend_account_service.rb
Normal file
52
app/services/unsuspend_account_service.rb
Normal file
@ -0,0 +1,52 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class UnsuspendAccountService < BaseService
|
||||
def call(account)
|
||||
@account = account
|
||||
|
||||
unsuspend!
|
||||
merge_into_home_timelines!
|
||||
merge_into_list_timelines!
|
||||
publish_media_attachments!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def unsuspend!
|
||||
@account.unsuspend! if @account.suspended?
|
||||
end
|
||||
|
||||
def merge_into_home_timelines!
|
||||
@account.followers_for_local_distribution.find_each do |follower|
|
||||
FeedManager.instance.merge_into_timeline(@account, follower)
|
||||
end
|
||||
end
|
||||
|
||||
def merge_into_list_timelines!
|
||||
@account.lists_for_local_distribution.find_each do |list|
|
||||
FeedManager.instance.merge_into_list(@account, list)
|
||||
end
|
||||
end
|
||||
|
||||
def publish_media_attachments!
|
||||
attachment_names = MediaAttachment.attachment_definitions.keys
|
||||
|
||||
@account.media_attachments.find_each do |media_attachment|
|
||||
attachment_names.each do |attachment_name|
|
||||
attachment = media_attachment.public_send(attachment_name)
|
||||
styles = [:original] | attachment.styles.keys
|
||||
|
||||
styles.each do |style|
|
||||
case Paperclip::Attachment.default_options[:storage]
|
||||
when :s3
|
||||
attachment.s3_object(style).acl.put(Paperclip::Attachment.default_options[:s3_permissions])
|
||||
when :fog
|
||||
# Not supported
|
||||
when :filesystem
|
||||
FileUtils.chmod(0o666 & ~File.umask, attachment.path(style))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Reference in New Issue
Block a user