add new privacy option to auto-defederate after a given timespan + add options to defederate and/or delete past posts + add `defed_in`/`parent:defed_in`/`thread:defed_in` bangtags + ui indicator for posts marked for auto-defederation
parent
1fbe7c3402
commit
67516a07db
|
@ -53,6 +53,7 @@ class Api::V1::StatusesController < Api::BaseController
|
|||
visibility: status_params[:visibility],
|
||||
scheduled_at: status_params[:scheduled_at],
|
||||
delete_after: status_params[:delete_after],
|
||||
defederate_after: status_params[:defederate_after],
|
||||
sharekey: status_params[:sharekey],
|
||||
application: doorkeeper_token.application,
|
||||
poll: status_params[:poll],
|
||||
|
@ -100,6 +101,7 @@ class Api::V1::StatusesController < Api::BaseController
|
|||
:sharekey,
|
||||
:scheduled_at,
|
||||
:delete_after,
|
||||
:defederate_after,
|
||||
:content_type,
|
||||
media_ids: [],
|
||||
poll: [
|
||||
|
|
|
@ -12,6 +12,12 @@ class Settings::PreferencesController < Settings::BaseController
|
|||
def update
|
||||
user_settings.update(user_settings_params.to_h)
|
||||
|
||||
MarkExpiredStatusesWorker.perform_async(
|
||||
current_account.id,
|
||||
truthy_param?(:setting_defederate_old),
|
||||
truthy_param?(:setting_lifespan_old)
|
||||
)
|
||||
|
||||
if current_user.update(user_params)
|
||||
I18n.locale = current_user.locale
|
||||
toggle_filters
|
||||
|
@ -85,6 +91,7 @@ class Settings::PreferencesController < Settings::BaseController
|
|||
:setting_max_public_history,
|
||||
:setting_max_public_access,
|
||||
:setting_roar_lifespan,
|
||||
:setting_roar_defederate,
|
||||
:setting_delayed_roars,
|
||||
:setting_delayed_for,
|
||||
:setting_boost_interval,
|
||||
|
|
|
@ -64,6 +64,9 @@ export default class StatusIcons extends React.PureComponent {
|
|||
{status.get('delete_after') ? (
|
||||
<i className='fa fa-clock-o' title={new Date(status.get('delete_after'))} aria-hidden='true' />
|
||||
) : null}
|
||||
{status.get('defederate_after') ? (
|
||||
<i className='fa fa-calendar-times-o' title={new Date(status.get('defederate_after'))} aria-hidden='true' />
|
||||
) : null}
|
||||
{status.get('reject_replies') ? (
|
||||
<i className='fa fa-microphone-slash' title='Rejecting replies' aria-hidden='true' />
|
||||
) : null}
|
||||
|
|
|
@ -131,6 +131,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
|
|||
let favouriteLink = '';
|
||||
let sharekeyLinks = '';
|
||||
let destructIcon = '';
|
||||
let defederateIcon = '';
|
||||
let rejectIcon = '';
|
||||
|
||||
if (this.props.measureHeight) {
|
||||
|
@ -256,6 +257,14 @@ export default class DetailedStatus extends ImmutablePureComponent {
|
|||
)
|
||||
}
|
||||
|
||||
if (status.get('defederate_after')) {
|
||||
defederateIcon = (
|
||||
<span>
|
||||
<i className='fa fa-calendar-times-o' title={new Date(status.get('defederate_after'))} /> ·
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
if (status.get('reject_replies')) {
|
||||
rejectIcon = (
|
||||
<span>
|
||||
|
@ -285,7 +294,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
|
|||
/>
|
||||
|
||||
<div className='detailed-status__meta'>
|
||||
{sharekeyLinks} {reblogLink} · {favouriteLink} · {destructIcon} {rejectIcon} <VisibilityIcon visibility={status.get('visibility')} />
|
||||
{sharekeyLinks} {reblogLink} · {favouriteLink} · {defederateIcon} {destructIcon} {rejectIcon} <VisibilityIcon visibility={status.get('visibility')} />
|
||||
<a className='detailed-status__datetime' href={status.get('url')} target='_blank' rel='noopener'>
|
||||
<FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' />
|
||||
</a>
|
||||
|
|
|
@ -59,6 +59,21 @@ class Bangtags
|
|||
['all', 'live'] => ['live', 'all'],
|
||||
['all', 'lifespan'] => ['lifespan', 'all'],
|
||||
['all', 'delete_in'] => ['delete_in', 'all'],
|
||||
|
||||
['parent', 'd'] => ['defederate_in', 'parent'],
|
||||
['parent', 'defed'] => ['defederate_in', 'parent'],
|
||||
['parent', 'defed_in'] => ['defederate_in', 'parent'],
|
||||
['parent', 'defederate'] => ['defederate_in', 'parent'],
|
||||
|
||||
['thread', 'd'] => ['defederate_in', 'thread'],
|
||||
['thread', 'defed'] => ['defederate_in', 'thread'],
|
||||
['thread', 'defed_in'] => ['defederate_in', 'thread'],
|
||||
['thread', 'defederate'] => ['defederate_in', 'thread'],
|
||||
|
||||
['all', 'd'] => ['defederate_in', 'all'],
|
||||
['all', 'defed'] => ['defederate_in', 'all'],
|
||||
['all', 'defed_in'] => ['defederate_in', 'all'],
|
||||
['all', 'defederate'] => ['defederate_in', 'all'],
|
||||
}
|
||||
|
||||
# sections of the final status text
|
||||
|
@ -730,6 +745,50 @@ class Bangtags
|
|||
s.delete_after = delete_after
|
||||
Rails.cache.delete("statuses/#{s.id}")
|
||||
end
|
||||
when 'd', 'defed', 'defed_in', 'defederate', 'defederate_in'
|
||||
chunk = nil
|
||||
next if cmd[1].nil?
|
||||
case cmd[1].downcase
|
||||
when 'parent', 'thread', 'all'
|
||||
s = cmd[1].downcase.to_sym
|
||||
s = @parent_status if s == :parent
|
||||
next unless s == :all || @parent_status.present?
|
||||
next unless s == :thread || s == :all || @parent_status.account_id == @account.id
|
||||
i = cmd[2].to_i
|
||||
unit = cmd[3].present? ? cmd[3].downcase : 'minutes'
|
||||
else
|
||||
s = @status
|
||||
i = cmd[1].to_i
|
||||
unit = cmd[2].present? ? cmd[2].downcase : 'minutes'
|
||||
end
|
||||
defederate_after = case unit
|
||||
when 'min', 'mins', 'minute', 'minutes'
|
||||
i.minutes
|
||||
when 'h', 'hr', 'hrs', 'hour', 'hours'
|
||||
i.hours
|
||||
when 'd', 'dy', 'dys', 'day', 'days'
|
||||
i.days
|
||||
when 'w', 'wk', 'wks', 'week', 'weeks'
|
||||
i.weeks
|
||||
when 'm', 'mn', 'mns', 'month', 'months'
|
||||
i.months
|
||||
when 'y', 'yr', 'yrs', 'year', 'years'
|
||||
i.years
|
||||
end
|
||||
if s == :thread
|
||||
@parent_status.conversation.statuses.where(account_id: @account.id).find_each do |s|
|
||||
s.defederate_after = defederate_after
|
||||
Rails.cache.delete("statuses/#{s.id}")
|
||||
end
|
||||
elsif s == :all
|
||||
@account.statuses.find_each do |s|
|
||||
s.defederate_after = defederate_after
|
||||
Rails.cache.delete("statuses/#{s.id}")
|
||||
end
|
||||
else
|
||||
s.defederate_after = defederate_after
|
||||
Rails.cache.delete("statuses/#{s.id}")
|
||||
end
|
||||
when 'keysmash'
|
||||
keyboard = [
|
||||
'asdf', 'jkl;',
|
||||
|
|
|
@ -42,6 +42,9 @@ class UserSettingsDecorator
|
|||
user.settings['max_public_history'] = max_public_history_preference if change?('setting_max_public_history')
|
||||
user.settings['max_public_access'] = max_public_access_preference if change?('setting_max_public_access')
|
||||
user.settings['roar_lifespan'] = roar_lifespan_preference if change?('setting_roar_lifespan')
|
||||
user.settings['roar_lifespan_old'] = roar_lifespan_old_preference if change?('setting_roar_lifespan_old')
|
||||
user.settings['roar_defederate'] = roar_defederate_preference if change?('setting_roar_defederate')
|
||||
user.settings['roar_defederate_old'] = roar_defederate_old_preference if change?('setting_roar_defederate_old')
|
||||
user.settings['delayed_roars'] = delayed_roars_preference if change?('setting_delayed_roars')
|
||||
user.settings['delayed_for'] = delayed_for_preference if change?('setting_delayed_for')
|
||||
user.settings['boost_interval'] = boost_interval_preference if change?('setting_boost_interval')
|
||||
|
@ -160,6 +163,18 @@ class UserSettingsDecorator
|
|||
settings['setting_roar_lifespan']
|
||||
end
|
||||
|
||||
def roar_lifespan_old_preference
|
||||
settings['setting_roar_lifespan_old']
|
||||
end
|
||||
|
||||
def roar_defederate_preference
|
||||
settings['setting_roar_defederate']
|
||||
end
|
||||
|
||||
def roar_defederate_old_preference
|
||||
settings['setting_roar_defederate_old']
|
||||
end
|
||||
|
||||
def delayed_for_preference
|
||||
settings['setting_delayed_for']
|
||||
end
|
||||
|
|
|
@ -135,6 +135,9 @@ class Account < ApplicationRecord
|
|||
:max_public_history,
|
||||
:max_public_access,
|
||||
:roar_lifespan,
|
||||
:roar_lifespan_old,
|
||||
:roar_defederate,
|
||||
:roar_defederate_old,
|
||||
:delayed_roars?,
|
||||
|
||||
:hides_public_profile?,
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: defederating_statuses
|
||||
#
|
||||
# id :bigint(8) not null, primary key
|
||||
# status_id :bigint(8)
|
||||
# defederate_after :datetime
|
||||
#
|
||||
|
||||
class DefederatingStatus < ApplicationRecord
|
||||
belongs_to :status, inverse_of: :defederating_status
|
||||
|
||||
validate :validate_future_date
|
||||
validates :status_id, uniqueness: true
|
||||
|
||||
private
|
||||
|
||||
def validate_future_date
|
||||
errors.add(:defederate_after, I18n.t('defederating_statuses.too_soon')) if defederate_after.present? && defederate_after < Time.now.utc + PostStatusService::MIN_DESTRUCT_OFFSET
|
||||
end
|
||||
end
|
|
@ -11,6 +11,7 @@ class DestructingStatus < ApplicationRecord
|
|||
belongs_to :status, inverse_of: :destructing_status
|
||||
|
||||
validate :validate_future_date
|
||||
validates :status_id, uniqueness: true
|
||||
|
||||
private
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ class Status < ApplicationRecord
|
|||
has_one :status_stat, inverse_of: :status
|
||||
has_one :poll, inverse_of: :status, dependent: :destroy
|
||||
has_one :destructing_status, inverse_of: :status, dependent: :destroy
|
||||
has_one :defederating_status, inverse_of: :status, dependent: :destroy
|
||||
has_one :imported_status, inverse_of: :status, dependent: :destroy
|
||||
has_one :sharekey, inverse_of: :status, dependent: :destroy
|
||||
|
||||
|
@ -284,6 +285,10 @@ class Status < ApplicationRecord
|
|||
end
|
||||
|
||||
def delete_after=(value)
|
||||
if defederate_after && defederate_after < (Time.now.utc + 5.minutes + value)
|
||||
value = 5.minutes + value
|
||||
end
|
||||
|
||||
if destructing_status.nil?
|
||||
DestructingStatus.create!(status_id: id, delete_after: Time.now.utc + value)
|
||||
else
|
||||
|
@ -291,6 +296,20 @@ class Status < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
def defederate_after
|
||||
defederating_status&.defederate_after
|
||||
end
|
||||
|
||||
def defederate_after=(value)
|
||||
return unless delete_after.nil? || delete_after >= (Time.now.utc + 5.minutes + value)
|
||||
|
||||
if defederating_status.nil?
|
||||
DefederatingStatus.create!(status_id: id, defederate_after: Time.now.utc + value)
|
||||
else
|
||||
defederating_status.defederate_after = Time.now.utc + value
|
||||
end
|
||||
end
|
||||
|
||||
def mark_for_mass_destruction!
|
||||
@marked_for_mass_destruction = true
|
||||
end
|
||||
|
|
|
@ -148,6 +148,9 @@ class User < ApplicationRecord
|
|||
:max_public_history,
|
||||
:max_public_access,
|
||||
:roar_lifespan,
|
||||
:roar_lifespan_old,
|
||||
:roar_defederate,
|
||||
:roar_defederate_old,
|
||||
:delayed_roars,
|
||||
:delayed_for,
|
||||
:boost_interval,
|
||||
|
@ -340,6 +343,18 @@ class User < ApplicationRecord
|
|||
@_roar_lifespan ||= [0, (settings.roar_lifespan || 0).to_i].max
|
||||
end
|
||||
|
||||
def roar_lifespan_old
|
||||
@_roar_lifespan_old ||= (settings.roar_lifespan_old || false)
|
||||
end
|
||||
|
||||
def roar_defederate
|
||||
@_roar_defederate ||= [0, (settings.roar_defederate || 0).to_i].max
|
||||
end
|
||||
|
||||
def roar_defederate_old
|
||||
@_roar_defederate_old ||= (settings.roar_defederate_old || false)
|
||||
end
|
||||
|
||||
def delayed_roars?
|
||||
@delayed_roars ||= (settings.delayed_roars || false)
|
||||
end
|
||||
|
|
|
@ -16,6 +16,7 @@ class REST::StatusSerializer < ActiveModel::Serializer
|
|||
attribute :local_only if :local?
|
||||
attribute :sharekey, if: :has_sharekey?
|
||||
attribute :delete_after, if: :current_user?
|
||||
attribute :defederate_after, if: :current_user?
|
||||
|
||||
attribute :content, unless: :source_requested?
|
||||
attribute :text, if: :source_requested?
|
||||
|
@ -154,6 +155,10 @@ class REST::StatusSerializer < ActiveModel::Serializer
|
|||
object.delete_after
|
||||
end
|
||||
|
||||
def defederate_after
|
||||
object.defederate_after
|
||||
end
|
||||
|
||||
def reject_replies
|
||||
object.reject_replies == true
|
||||
end
|
||||
|
|
|
@ -30,6 +30,7 @@ class PostStatusService < BaseService
|
|||
# @option [String] :language
|
||||
# @option [String] :scheduled_at
|
||||
# @option [String] :delete_after
|
||||
# @option [String] :defederate_after
|
||||
# @option [Account] :mentions Optional accounts to mention out-of-body
|
||||
# @option [Boolean] :noreplies Author does not accept replies
|
||||
# @option [Boolean] :nocrawl Optional skip link card generation
|
||||
|
@ -76,6 +77,7 @@ class PostStatusService < BaseService
|
|||
distribute: @options[:distribute],
|
||||
nocrawl: @options[:nocrawl],
|
||||
delete_after: @delete_after.nil? ? nil : @delete_after + 1.minute,
|
||||
defederate_after: @defederate_after.nil? ? nil : @defederate_after + 1.minute,
|
||||
reject_replies: @options[:noreplies] || false,
|
||||
}.compact
|
||||
|
||||
|
@ -201,6 +203,18 @@ class PostStatusService < BaseService
|
|||
end
|
||||
@delete_after = nil if @delete_after.present? && (@delete_after < MIN_DESTRUCT_OFFSET)
|
||||
|
||||
case @options[:defederate_after].class
|
||||
when NilClass
|
||||
@defederate_after = @account.user.setting_roar_defederate.to_i.days
|
||||
when ActiveSupport::Duration
|
||||
@defederate_after = @options[:defederate_after]
|
||||
when Integer
|
||||
@defederate_after = @options[:defederate_after].minutes
|
||||
when Float
|
||||
@defederate_after = @options[:defederate_after].minutes
|
||||
end
|
||||
@defederate_after = nil if @defederate_after.present? && (@defederate_after < MIN_DESTRUCT_OFFSET)
|
||||
|
||||
rescue ArgumentError
|
||||
raise ActiveRecord::RecordInvalid
|
||||
end
|
||||
|
@ -310,6 +324,7 @@ class PostStatusService < BaseService
|
|||
visibility: @visibility,
|
||||
local_only: @local_only,
|
||||
delete_after: @delete_after,
|
||||
defederate_after: @defederate_after,
|
||||
reject_replies: @options[:noreplies] || false,
|
||||
sharekey: @options[:sharekey],
|
||||
language: language_from_option(@options[:language]) || @account.user_default_language&.presence || 'en',
|
||||
|
|
|
@ -16,22 +16,24 @@ class RemoveStatusService < BaseService
|
|||
@stream_entry = status.stream_entry
|
||||
@options = options
|
||||
|
||||
RedisLock.acquire(lock_options) do |lock|
|
||||
if lock.acquired?
|
||||
remove_from_queued
|
||||
remove_from_self if status.account.local?
|
||||
remove_from_followers
|
||||
remove_from_lists
|
||||
remove_from_affected
|
||||
remove_reblogs
|
||||
remove_from_hashtags
|
||||
remove_from_public
|
||||
remove_from_media if status.media_attachments.any?
|
||||
remove_from_direct if status.direct_visibility?
|
||||
unless options[:defederate_only]
|
||||
RedisLock.acquire(lock_options) do |lock|
|
||||
if lock.acquired?
|
||||
remove_from_queued
|
||||
remove_from_self if status.account.local?
|
||||
remove_from_followers
|
||||
remove_from_lists
|
||||
remove_from_affected
|
||||
remove_reblogs
|
||||
remove_from_hashtags
|
||||
remove_from_public
|
||||
remove_from_media if status.media_attachments.any?
|
||||
remove_from_direct if status.direct_visibility?
|
||||
|
||||
@status.destroy!
|
||||
else
|
||||
raise Mastodon::RaceConditionError
|
||||
@status.destroy!
|
||||
else
|
||||
raise Mastodon::RaceConditionError
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -44,6 +46,9 @@ class RemoveStatusService < BaseService
|
|||
|
||||
remove_from_remote_followers
|
||||
remove_from_remote_affected
|
||||
|
||||
@status.update(local_only: true) if options[:defederate_only]
|
||||
Rails.cache.delete("statuses/#{@status.id}")
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -17,9 +17,21 @@
|
|||
= f.input :setting_default_privacy, collection: Status.selectable_visibilities, wrapper: :with_floating_label, include_blank: false, label_method: lambda { |visibility| safe_join([I18n.t("statuses.visibilities.#{visibility}"), content_tag(:span, I18n.t("statuses.visibilities.#{visibility}_long"), class: 'hint')]) }, required: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
|
||||
|
||||
.fields-group
|
||||
= f.input :setting_max_public_history, collection: [1, 3, 6, 7, 14, 30, 60, 90, 180, 365, 730, 1095, 2190], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.lifespan.#{item}")]) }, selected: current_user.max_public_history
|
||||
= f.input :setting_max_public_access, collection: [1, 3, 6, 7, 14, 30, 60, 90, 180, 365, 730, 1095, 2190], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.lifespan.#{item}")]) }, selected: current_user.max_public_access
|
||||
= f.input :setting_roar_lifespan, collection: [0, 1, 3, 6, 7, 14, 30, 60, 90, 180, 365, 730, 1095, 2190], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.lifespan.#{item}")]) }, selected: current_user.roar_lifespan
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= f.input :setting_max_public_history, collection: [1, 3, 6, 7, 14, 30, 60, 90, 180, 365, 730, 1095, 2190], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.lifespan.#{item}")]) }, selected: current_user.max_public_history
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= f.input :setting_max_public_access, collection: [1, 3, 6, 7, 14, 30, 60, 90, 180, 365, 730, 1095, 2190], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.lifespan.#{item}")]) }, selected: current_user.max_public_access
|
||||
|
||||
.fields-group
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= f.input :setting_roar_defederate, collection: [0, 1, 3, 6, 7, 14, 30, 60, 90, 180, 365, 730, 1095, 2190], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.lifespan.#{item}")]) }, selected: current_user.roar_defederate
|
||||
= f.input :setting_roar_defederate_old, as: :boolean, wrapper: :with_label
|
||||
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= f.input :setting_roar_lifespan, collection: [0, 1, 3, 6, 7, 14, 30, 60, 90, 180, 365, 730, 1095, 2190], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.lifespan.#{item}")]) }, selected: current_user.roar_lifespan
|
||||
= f.input :setting_roar_lifespan_old, as: :boolean, wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= f.input :setting_default_sensitive, as: :boolean, wrapper: :with_label
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DefederateStatusWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options unique: :until_executed
|
||||
|
||||
def perform(defederating_status_id)
|
||||
defederating_status = DefederatingStatus.find(defederating_status_id)
|
||||
defederating_status.destroy!
|
||||
|
||||
RemoveStatusService.new.call(defederating_status.status, defederate_only: true)
|
||||
true
|
||||
rescue ActiveRecord::RecordNotFound, ActiveRecord::RecordInvalid
|
||||
true
|
||||
end
|
||||
end
|
|
@ -0,0 +1,44 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MarkExpiredStatusesWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options queue: 'bulk'
|
||||
|
||||
def perform(account_id, defederate = false, lifespan = false)
|
||||
@account = Account.find(account_id)
|
||||
return if @account&.user.nil?
|
||||
@user = @account.user
|
||||
|
||||
@roar_defederate = @user.roar_defederate.to_i
|
||||
@roar_lifespan = @user.roar_lifespan.to_i
|
||||
|
||||
defederate = false if @roar_defederate == 0
|
||||
lifespan = false if @roar_lifespan == 0
|
||||
|
||||
return unless defederate || lifespan
|
||||
|
||||
offset = 30.minutes
|
||||
|
||||
@account.statuses.find_each do |status|
|
||||
modified = false
|
||||
|
||||
if defederate && !status.local_only? && status.updated_at < @roar_defederate.days.ago
|
||||
status.defederate_after = offset
|
||||
modified = true
|
||||
end
|
||||
|
||||
if lifespan && status.updated_at < @roar_lifespan.days.ago
|
||||
status.delete_after = offset + 30.minutes
|
||||
modified = true
|
||||
end
|
||||
|
||||
if modified
|
||||
Rails.cache.delete("statuses/#{status.id}")
|
||||
offset += 1.second
|
||||
end
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
true
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Scheduler::DefederatingStatusesScheduler
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options unique: :until_executed, retry: 0
|
||||
|
||||
def perform
|
||||
due_statuses.find_each do |defederating_status|
|
||||
DefederateStatusWorker.perform_async(defederating_status.id)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def due_statuses
|
||||
DefederatingStatus.where('defederate_after <= ?', Time.now.utc)
|
||||
end
|
||||
end
|
|
@ -885,6 +885,8 @@ en:
|
|||
too_soon: The scheduled timeframe must be at least 5 minutes into the future
|
||||
destructing_statuses:
|
||||
too_soon: The destruction timeframe must be at least 5 minutes into the future
|
||||
defederating_statuses:
|
||||
too_soon: The destruction timeframe must be at least 5 minutes into the future
|
||||
sessions:
|
||||
activity: Last activity
|
||||
browser: Browser
|
||||
|
|
|
@ -49,6 +49,8 @@ en:
|
|||
media_only: Hides text-only posts
|
||||
filters_enabled: Enables custom timeline filters which can be configured in the Filters tab.
|
||||
monsterfork_api: How much of Monsterfork features should be exposed to clients. Set to Basic or Vanilla if your Mastodon app is having problems with Monsterfork.
|
||||
setting_roar_lifespan_old: "<strong>This is a destructive operation!</strong><br>Back up your account before saving changes!<br>Will deselect after save"
|
||||
setting_roar_defederate_old: "<strong>This is an irreversible operation!</strong><br>Will deselect after save"
|
||||
featured_tag:
|
||||
name: 'You might want to use one of these:'
|
||||
imports:
|
||||
|
@ -131,6 +133,9 @@ en:
|
|||
setting_default_language: Posting language
|
||||
setting_default_privacy: Post privacy
|
||||
setting_roar_lifespan: Auto-delete new roars after
|
||||
setting_roar_lifespan_old: Include past roars
|
||||
setting_roar_defederate: Auto-defederate new roars after
|
||||
setting_roar_defederate_old: Include past roars
|
||||
setting_delayed_roars: Delayed publishing of roars for proofreading
|
||||
setting_delayed_for: Delay for
|
||||
setting_boost_interval: Automatically space out consecutive boosts
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
destructing_statuses_scheduler:
|
||||
every: '1m'
|
||||
class: Scheduler::DestructingStatusesScheduler
|
||||
defederatinging_statuses_scheduler:
|
||||
every: '1m'
|
||||
class: Scheduler::DefederatingStatusesScheduler
|
||||
boosts_scheduler:
|
||||
every: '1m'
|
||||
class: Scheduler::BoostsScheduler
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
class CreateDefederatingStatuses < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
create_table :defederating_statuses do |t|
|
||||
t.references :status, foreign_key: true
|
||||
t.datetime :defederate_after
|
||||
end
|
||||
safety_assured { add_index :defederating_statuses, :defederate_after }
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
class AddUniqueIndexesOnDefederatingAndDestructingStatuses < ActiveRecord::Migration[5.2]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def change
|
||||
remove_index :destructing_statuses, :status_id
|
||||
remove_index :defederating_statuses, :status_id
|
||||
|
||||
add_index :destructing_statuses, :status_id, unique: true, algorithm: :concurrently
|
||||
add_index :defederating_statuses, :status_id, unique: true, algorithm: :concurrently
|
||||
end
|
||||
end
|
|
@ -896,6 +896,36 @@ CREATE SEQUENCE public.custom_filters_id_seq
|
|||
ALTER SEQUENCE public.custom_filters_id_seq OWNED BY public.custom_filters.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: defederating_statuses; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.defederating_statuses (
|
||||
id bigint NOT NULL,
|
||||
status_id bigint,
|
||||
defederate_after timestamp without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: defederating_statuses_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.defederating_statuses_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: defederating_statuses_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.defederating_statuses_id_seq OWNED BY public.defederating_statuses.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: destructing_statuses; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -2623,6 +2653,13 @@ ALTER TABLE ONLY public.custom_emojis ALTER COLUMN id SET DEFAULT nextval('publi
|
|||
ALTER TABLE ONLY public.custom_filters ALTER COLUMN id SET DEFAULT nextval('public.custom_filters_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: defederating_statuses id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.defederating_statuses ALTER COLUMN id SET DEFAULT nextval('public.defederating_statuses_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: destructing_statuses id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -3084,6 +3121,14 @@ ALTER TABLE ONLY public.custom_filters
|
|||
ADD CONSTRAINT custom_filters_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: defederating_statuses defederating_statuses_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.defederating_statuses
|
||||
ADD CONSTRAINT defederating_statuses_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: destructing_statuses destructing_statuses_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -3696,6 +3741,20 @@ CREATE UNIQUE INDEX index_custom_emojis_on_shortcode_and_domain ON public.custom
|
|||
CREATE INDEX index_custom_filters_on_account_id ON public.custom_filters USING btree (account_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_defederating_statuses_on_defederate_after; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_defederating_statuses_on_defederate_after ON public.defederating_statuses USING btree (defederate_after);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_defederating_statuses_on_status_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE UNIQUE INDEX index_defederating_statuses_on_status_id ON public.defederating_statuses USING btree (status_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_destructing_statuses_on_delete_after; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -3707,7 +3766,7 @@ CREATE INDEX index_destructing_statuses_on_delete_after ON public.destructing_st
|
|||
-- Name: index_destructing_statuses_on_status_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_destructing_statuses_on_status_id ON public.destructing_statuses USING btree (status_id);
|
||||
CREATE UNIQUE INDEX index_destructing_statuses_on_status_id ON public.destructing_statuses USING btree (status_id);
|
||||
|
||||
|
||||
--
|
||||
|
@ -4979,6 +5038,14 @@ ALTER TABLE ONLY public.account_warnings
|
|||
ADD CONSTRAINT fk_rails_a7ebbb1e37 FOREIGN KEY (target_account_id) REFERENCES public.accounts(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: defederating_statuses fk_rails_af4e2f2cab; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.defederating_statuses
|
||||
ADD CONSTRAINT fk_rails_af4e2f2cab FOREIGN KEY (status_id) REFERENCES public.statuses(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: web_push_subscriptions fk_rails_b006f28dac; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -5399,6 +5466,8 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|||
('20200110214031'),
|
||||
('20200110221801'),
|
||||
('20200110221920'),
|
||||
('20200111042543');
|
||||
('20200111042543'),
|
||||
('20200114011918'),
|
||||
('20200114030940');
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue