mirror of
https://git.kescher.at/CatCatNya/catstodon.git
synced 2024-11-22 23:28:08 +01:00
Merge branch 'master' into glitch-soc/merge-upstream
This commit is contained in:
commit
6badf2d252
39 changed files with 271 additions and 155 deletions
4
Gemfile
4
Gemfile
|
@ -109,7 +109,7 @@ group :production, :test do
|
||||||
end
|
end
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
gem 'capybara', '~> 3.18'
|
gem 'capybara', '~> 3.19'
|
||||||
gem 'climate_control', '~> 0.2'
|
gem 'climate_control', '~> 0.2'
|
||||||
gem 'faker', '~> 1.9'
|
gem 'faker', '~> 1.9'
|
||||||
gem 'microformats', '~> 4.1'
|
gem 'microformats', '~> 4.1'
|
||||||
|
@ -129,7 +129,7 @@ group :development do
|
||||||
gem 'letter_opener', '~> 1.7'
|
gem 'letter_opener', '~> 1.7'
|
||||||
gem 'letter_opener_web', '~> 1.3'
|
gem 'letter_opener_web', '~> 1.3'
|
||||||
gem 'memory_profiler'
|
gem 'memory_profiler'
|
||||||
gem 'rubocop', '~> 0.68', require: false
|
gem 'rubocop', '~> 0.69', require: false
|
||||||
gem 'brakeman', '~> 4.5', require: false
|
gem 'brakeman', '~> 4.5', require: false
|
||||||
gem 'bundler-audit', '~> 0.6', require: false
|
gem 'bundler-audit', '~> 0.6', require: false
|
||||||
gem 'scss_lint', '~> 0.58', require: false
|
gem 'scss_lint', '~> 0.58', require: false
|
||||||
|
|
16
Gemfile.lock
16
Gemfile.lock
|
@ -103,7 +103,7 @@ GEM
|
||||||
ffi (~> 1.10.0)
|
ffi (~> 1.10.0)
|
||||||
bootsnap (1.4.4)
|
bootsnap (1.4.4)
|
||||||
msgpack (~> 1.0)
|
msgpack (~> 1.0)
|
||||||
brakeman (4.5.0)
|
brakeman (4.5.1)
|
||||||
browser (2.5.3)
|
browser (2.5.3)
|
||||||
builder (3.2.3)
|
builder (3.2.3)
|
||||||
bullet (6.0.0)
|
bullet (6.0.0)
|
||||||
|
@ -129,7 +129,7 @@ GEM
|
||||||
sshkit (~> 1.3)
|
sshkit (~> 1.3)
|
||||||
capistrano-yarn (2.0.2)
|
capistrano-yarn (2.0.2)
|
||||||
capistrano (~> 3.0)
|
capistrano (~> 3.0)
|
||||||
capybara (3.18.0)
|
capybara (3.19.1)
|
||||||
addressable
|
addressable
|
||||||
mini_mime (>= 0.1.3)
|
mini_mime (>= 0.1.3)
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.8)
|
||||||
|
@ -529,13 +529,13 @@ GEM
|
||||||
rspec-core (~> 3.0, >= 3.0.0)
|
rspec-core (~> 3.0, >= 3.0.0)
|
||||||
sidekiq (>= 2.4.0)
|
sidekiq (>= 2.4.0)
|
||||||
rspec-support (3.8.0)
|
rspec-support (3.8.0)
|
||||||
rubocop (0.68.1)
|
rubocop (0.69.0)
|
||||||
jaro_winkler (~> 1.5.1)
|
jaro_winkler (~> 1.5.1)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 2.5, != 2.5.1.1)
|
parser (>= 2.6)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 1.4.0, < 1.6)
|
unicode-display_width (>= 1.4.0, < 1.7)
|
||||||
ruby-progressbar (1.10.0)
|
ruby-progressbar (1.10.0)
|
||||||
ruby-saml (1.9.0)
|
ruby-saml (1.9.0)
|
||||||
nokogiri (>= 1.5.10)
|
nokogiri (>= 1.5.10)
|
||||||
|
@ -630,7 +630,7 @@ GEM
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
unf_ext (0.0.7.5)
|
unf_ext (0.0.7.5)
|
||||||
unicode-display_width (1.5.0)
|
unicode-display_width (1.6.0)
|
||||||
uniform_notifier (1.12.1)
|
uniform_notifier (1.12.1)
|
||||||
warden (1.2.8)
|
warden (1.2.8)
|
||||||
rack (>= 2.0.6)
|
rack (>= 2.0.6)
|
||||||
|
@ -673,7 +673,7 @@ DEPENDENCIES
|
||||||
capistrano-rails (~> 1.4)
|
capistrano-rails (~> 1.4)
|
||||||
capistrano-rbenv (~> 2.1)
|
capistrano-rbenv (~> 2.1)
|
||||||
capistrano-yarn (~> 2.0)
|
capistrano-yarn (~> 2.0)
|
||||||
capybara (~> 3.18)
|
capybara (~> 3.19)
|
||||||
charlock_holmes (~> 0.7.6)
|
charlock_holmes (~> 0.7.6)
|
||||||
chewy (~> 5.0)
|
chewy (~> 5.0)
|
||||||
cld3 (~> 3.2.4)
|
cld3 (~> 3.2.4)
|
||||||
|
@ -751,7 +751,7 @@ DEPENDENCIES
|
||||||
rqrcode (~> 0.10)
|
rqrcode (~> 0.10)
|
||||||
rspec-rails (~> 3.8)
|
rspec-rails (~> 3.8)
|
||||||
rspec-sidekiq (~> 3.0)
|
rspec-sidekiq (~> 3.0)
|
||||||
rubocop (~> 0.68)
|
rubocop (~> 0.69)
|
||||||
sanitize (~> 5.0)
|
sanitize (~> 5.0)
|
||||||
scss_lint (~> 0.58)
|
scss_lint (~> 0.58)
|
||||||
sidekiq (~> 5.2)
|
sidekiq (~> 5.2)
|
||||||
|
|
|
@ -41,7 +41,7 @@ module Admin
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
authorize @domain_block, :destroy?
|
authorize @domain_block, :destroy?
|
||||||
UnblockDomainService.new.call(@domain_block, retroactive_unblock?)
|
UnblockDomainService.new.call(@domain_block)
|
||||||
log_action :destroy, @domain_block
|
log_action :destroy, @domain_block
|
||||||
redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.destroyed_msg')
|
redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.destroyed_msg')
|
||||||
end
|
end
|
||||||
|
@ -53,11 +53,7 @@ module Admin
|
||||||
end
|
end
|
||||||
|
|
||||||
def resource_params
|
def resource_params
|
||||||
params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports, :retroactive)
|
params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports)
|
||||||
end
|
|
||||||
|
|
||||||
def retroactive_unblock?
|
|
||||||
ActiveRecord::Type.lookup(:boolean).cast(resource_params[:retroactive])
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -64,7 +64,7 @@ class HomeController < ApplicationController
|
||||||
if request.path.start_with?('/web')
|
if request.path.start_with?('/web')
|
||||||
new_user_session_path
|
new_user_session_path
|
||||||
elsif single_user_mode?
|
elsif single_user_mode?
|
||||||
short_account_path(Account.local.where(suspended: false).first)
|
short_account_path(Account.local.without_suspended.first)
|
||||||
else
|
else
|
||||||
about_path
|
about_path
|
||||||
end
|
end
|
||||||
|
|
|
@ -356,6 +356,7 @@ class Status extends ImmutablePureComponent {
|
||||||
{prepend}
|
{prepend}
|
||||||
|
|
||||||
<div className={classNames('status', `status-${status.get('visibility')}`, { 'status-reply': !!status.get('in_reply_to_id'), muted: this.props.muted, read: unread === false })} data-id={status.get('id')}>
|
<div className={classNames('status', `status-${status.get('visibility')}`, { 'status-reply': !!status.get('in_reply_to_id'), muted: this.props.muted, read: unread === false })} data-id={status.get('id')}>
|
||||||
|
<div className='status__expand' onClick={this.handleClick} role='presentation' />
|
||||||
<div className='status__info'>
|
<div className='status__info'>
|
||||||
<a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener'><RelativeTimestamp timestamp={status.get('created_at')} /></a>
|
<a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener'><RelativeTimestamp timestamp={status.get('created_at')} /></a>
|
||||||
|
|
||||||
|
|
|
@ -331,7 +331,7 @@ export default function compose(state = initialState, action) {
|
||||||
}));
|
}));
|
||||||
case REDRAFT:
|
case REDRAFT:
|
||||||
return state.withMutations(map => {
|
return state.withMutations(map => {
|
||||||
map.set('text', action.raw_content || unescapeHTML(expandMentions(action.status)));
|
map.set('text', action.raw_text || unescapeHTML(expandMentions(action.status)));
|
||||||
map.set('in_reply_to', action.status.get('in_reply_to_id'));
|
map.set('in_reply_to', action.status.get('in_reply_to_id'));
|
||||||
map.set('privacy', action.status.get('visibility'));
|
map.set('privacy', action.status.get('visibility'));
|
||||||
map.set('media_attachments', action.status.get('media_attachments'));
|
map.set('media_attachments', action.status.get('media_attachments'));
|
||||||
|
|
|
@ -162,7 +162,7 @@
|
||||||
.actions-modal ul li:not(:empty) a:focus button,
|
.actions-modal ul li:not(:empty) a:focus button,
|
||||||
.actions-modal ul li:not(:empty) a:hover,
|
.actions-modal ul li:not(:empty) a:hover,
|
||||||
.actions-modal ul li:not(:empty) a:hover button,
|
.actions-modal ul li:not(:empty) a:hover button,
|
||||||
.admin-wrapper .sidebar ul ul a.selected,
|
.admin-wrapper .sidebar ul li a.selected,
|
||||||
.simple_form .block-button,
|
.simple_form .block-button,
|
||||||
.simple_form .button,
|
.simple_form .button,
|
||||||
.simple_form button {
|
.simple_form button {
|
||||||
|
@ -230,6 +230,7 @@
|
||||||
.empty-column-indicator,
|
.empty-column-indicator,
|
||||||
.error-column {
|
.error-column {
|
||||||
color: $primary-text-color;
|
color: $primary-text-color;
|
||||||
|
background: $white;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change the default colors used on some parts of the profile pages
|
// Change the default colors used on some parts of the profile pages
|
||||||
|
|
|
@ -1412,6 +1412,15 @@ a.account__display-name {
|
||||||
width: 48px;
|
width: 48px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.status__expand {
|
||||||
|
width: 68px;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.muted {
|
.muted {
|
||||||
.status__content p,
|
.status__content p,
|
||||||
.status__content a {
|
.status__content a {
|
||||||
|
|
|
@ -187,7 +187,7 @@ class Formatter
|
||||||
end
|
end
|
||||||
|
|
||||||
def rewrite(text, entities)
|
def rewrite(text, entities)
|
||||||
chars = text.to_s.to_char_a
|
text = text.to_s
|
||||||
|
|
||||||
# Sort by start index
|
# Sort by start index
|
||||||
entities = entities.sort_by do |entity|
|
entities = entities.sort_by do |entity|
|
||||||
|
@ -199,12 +199,12 @@ class Formatter
|
||||||
|
|
||||||
last_index = entities.reduce(0) do |index, entity|
|
last_index = entities.reduce(0) do |index, entity|
|
||||||
indices = entity.respond_to?(:indices) ? entity.indices : entity[:indices]
|
indices = entity.respond_to?(:indices) ? entity.indices : entity[:indices]
|
||||||
result << encode(chars[index...indices.first].join)
|
result << encode(text[index...indices.first])
|
||||||
result << yield(entity)
|
result << yield(entity)
|
||||||
indices.last
|
indices.last
|
||||||
end
|
end
|
||||||
|
|
||||||
result << encode(chars[last_index..-1].join)
|
result << encode(text[last_index..-1])
|
||||||
|
|
||||||
result.flatten.join
|
result.flatten.join
|
||||||
end
|
end
|
||||||
|
@ -231,23 +231,14 @@ class Formatter
|
||||||
# Note: I couldn't obtain list_slug with @user/list-name format
|
# Note: I couldn't obtain list_slug with @user/list-name format
|
||||||
# for mention so this requires additional check
|
# for mention so this requires additional check
|
||||||
special = Extractor.extract_urls_with_indices(escaped, options).map do |extract|
|
special = Extractor.extract_urls_with_indices(escaped, options).map do |extract|
|
||||||
# exactly one of :url, :hashtag, :screen_name, :cashtag keys is present
|
|
||||||
key = (extract.keys & [:url, :hashtag, :screen_name, :cashtag]).first
|
|
||||||
|
|
||||||
new_indices = [
|
new_indices = [
|
||||||
old_to_new_index.find_index(extract[:indices].first),
|
old_to_new_index.find_index(extract[:indices].first),
|
||||||
old_to_new_index.find_index(extract[:indices].last),
|
old_to_new_index.find_index(extract[:indices].last),
|
||||||
]
|
]
|
||||||
|
|
||||||
has_prefix_char = [:hashtag, :screen_name, :cashtag].include?(key)
|
|
||||||
value_indices = [
|
|
||||||
new_indices.first + (has_prefix_char ? 1 : 0), # account for #, @ or $
|
|
||||||
new_indices.last - 1,
|
|
||||||
]
|
|
||||||
|
|
||||||
next extract.merge(
|
next extract.merge(
|
||||||
:indices => new_indices,
|
indices: new_indices,
|
||||||
key => text[value_indices.first..value_indices.last]
|
url: text[new_indices.first..new_indices.last - 1]
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,6 @@
|
||||||
# header_updated_at :datetime
|
# header_updated_at :datetime
|
||||||
# avatar_remote_url :string
|
# avatar_remote_url :string
|
||||||
# subscription_expires_at :datetime
|
# subscription_expires_at :datetime
|
||||||
# silenced :boolean default(FALSE), not null
|
|
||||||
# suspended :boolean default(FALSE), not null
|
|
||||||
# locked :boolean default(FALSE), not null
|
# locked :boolean default(FALSE), not null
|
||||||
# header_remote_url :string default(""), not null
|
# header_remote_url :string default(""), not null
|
||||||
# last_webfingered_at :datetime
|
# last_webfingered_at :datetime
|
||||||
|
@ -45,6 +43,8 @@
|
||||||
# actor_type :string
|
# actor_type :string
|
||||||
# discoverable :boolean
|
# discoverable :boolean
|
||||||
# also_known_as :string is an Array
|
# also_known_as :string is an Array
|
||||||
|
# silenced_at :datetime
|
||||||
|
# suspended_at :datetime
|
||||||
#
|
#
|
||||||
|
|
||||||
class Account < ApplicationRecord
|
class Account < ApplicationRecord
|
||||||
|
@ -86,10 +86,10 @@ class Account < ApplicationRecord
|
||||||
scope :local, -> { where(domain: nil) }
|
scope :local, -> { where(domain: nil) }
|
||||||
scope :expiring, ->(time) { remote.where.not(subscription_expires_at: nil).where('subscription_expires_at < ?', time) }
|
scope :expiring, ->(time) { remote.where.not(subscription_expires_at: nil).where('subscription_expires_at < ?', time) }
|
||||||
scope :partitioned, -> { order(Arel.sql('row_number() over (partition by domain)')) }
|
scope :partitioned, -> { order(Arel.sql('row_number() over (partition by domain)')) }
|
||||||
scope :silenced, -> { where(silenced: true) }
|
scope :silenced, -> { where.not(silenced_at: nil) }
|
||||||
scope :suspended, -> { where(suspended: true) }
|
scope :suspended, -> { where.not(suspended_at: nil) }
|
||||||
scope :without_suspended, -> { where(suspended: false) }
|
scope :without_suspended, -> { where(suspended_at: nil) }
|
||||||
scope :without_silenced, -> { where(silenced: false) }
|
scope :without_silenced, -> { where(silenced_at: nil) }
|
||||||
scope :recent, -> { reorder(id: :desc) }
|
scope :recent, -> { reorder(id: :desc) }
|
||||||
scope :bots, -> { where(actor_type: %w(Application Service)) }
|
scope :bots, -> { where(actor_type: %w(Application Service)) }
|
||||||
scope :alphabetic, -> { order(domain: :asc, username: :asc) }
|
scope :alphabetic, -> { order(domain: :asc, username: :asc) }
|
||||||
|
@ -169,25 +169,35 @@ class Account < ApplicationRecord
|
||||||
ResolveAccountService.new.call(acct)
|
ResolveAccountService.new.call(acct)
|
||||||
end
|
end
|
||||||
|
|
||||||
def silence!
|
def silenced?
|
||||||
update!(silenced: true)
|
silenced_at.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def silence!(date = nil)
|
||||||
|
date ||= Time.now.utc
|
||||||
|
update!(silenced_at: date)
|
||||||
end
|
end
|
||||||
|
|
||||||
def unsilence!
|
def unsilence!
|
||||||
update!(silenced: false)
|
update!(silenced_at: nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
def suspend!
|
def suspended?
|
||||||
|
suspended_at.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def suspend!(date = nil)
|
||||||
|
date ||= Time.now.utc
|
||||||
transaction do
|
transaction do
|
||||||
user&.disable! if local?
|
user&.disable! if local?
|
||||||
update!(suspended: true)
|
update!(suspended_at: date)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def unsuspend!
|
def unsuspend!
|
||||||
transaction do
|
transaction do
|
||||||
user&.enable! if local?
|
user&.enable! if local?
|
||||||
update!(suspended: false)
|
update!(suspended_at: nil)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -401,7 +411,7 @@ class Account < ApplicationRecord
|
||||||
ts_rank_cd(#{textsearch}, #{query}, 32) AS rank
|
ts_rank_cd(#{textsearch}, #{query}, 32) AS rank
|
||||||
FROM accounts
|
FROM accounts
|
||||||
WHERE #{query} @@ #{textsearch}
|
WHERE #{query} @@ #{textsearch}
|
||||||
AND accounts.suspended = false
|
AND accounts.suspended_at IS NULL
|
||||||
AND accounts.moved_to_account_id IS NULL
|
AND accounts.moved_to_account_id IS NULL
|
||||||
ORDER BY rank DESC
|
ORDER BY rank DESC
|
||||||
LIMIT ? OFFSET ?
|
LIMIT ? OFFSET ?
|
||||||
|
@ -429,7 +439,7 @@ class Account < ApplicationRecord
|
||||||
LEFT OUTER JOIN follows AS f ON (accounts.id = f.account_id AND f.target_account_id = ?) OR (accounts.id = f.target_account_id AND f.account_id = ?)
|
LEFT OUTER JOIN follows AS f ON (accounts.id = f.account_id AND f.target_account_id = ?) OR (accounts.id = f.target_account_id AND f.account_id = ?)
|
||||||
WHERE accounts.id IN (SELECT * FROM first_degree)
|
WHERE accounts.id IN (SELECT * FROM first_degree)
|
||||||
AND #{query} @@ #{textsearch}
|
AND #{query} @@ #{textsearch}
|
||||||
AND accounts.suspended = false
|
AND accounts.suspended_at IS NULL
|
||||||
AND accounts.moved_to_account_id IS NULL
|
AND accounts.moved_to_account_id IS NULL
|
||||||
GROUP BY accounts.id
|
GROUP BY accounts.id
|
||||||
ORDER BY rank DESC
|
ORDER BY rank DESC
|
||||||
|
@ -445,7 +455,7 @@ class Account < ApplicationRecord
|
||||||
FROM accounts
|
FROM accounts
|
||||||
LEFT OUTER JOIN follows AS f ON (accounts.id = f.account_id AND f.target_account_id = ?) OR (accounts.id = f.target_account_id AND f.account_id = ?)
|
LEFT OUTER JOIN follows AS f ON (accounts.id = f.account_id AND f.target_account_id = ?) OR (accounts.id = f.target_account_id AND f.account_id = ?)
|
||||||
WHERE #{query} @@ #{textsearch}
|
WHERE #{query} @@ #{textsearch}
|
||||||
AND accounts.suspended = false
|
AND accounts.suspended_at IS NULL
|
||||||
AND accounts.moved_to_account_id IS NULL
|
AND accounts.moved_to_account_id IS NULL
|
||||||
GROUP BY accounts.id
|
GROUP BY accounts.id
|
||||||
ORDER BY rank DESC
|
ORDER BY rank DESC
|
||||||
|
|
|
@ -13,7 +13,7 @@ module AccountFinderConcern
|
||||||
end
|
end
|
||||||
|
|
||||||
def representative
|
def representative
|
||||||
find_local(Setting.site_contact_username.strip.gsub(/\A@/, '')) || Account.local.find_by(suspended: false)
|
find_local(Setting.site_contact_username.strip.gsub(/\A@/, '')) || Account.local.without_suspended.first
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_local(username)
|
def find_local(username)
|
||||||
|
|
|
@ -17,8 +17,6 @@ class DomainBlock < ApplicationRecord
|
||||||
|
|
||||||
enum severity: [:silence, :suspend, :noop]
|
enum severity: [:silence, :suspend, :noop]
|
||||||
|
|
||||||
attr_accessor :retroactive
|
|
||||||
|
|
||||||
validates :domain, presence: true, uniqueness: true
|
validates :domain, presence: true, uniqueness: true
|
||||||
|
|
||||||
has_many :accounts, foreign_key: :domain, primary_key: :domain
|
has_many :accounts, foreign_key: :domain, primary_key: :domain
|
||||||
|
@ -36,4 +34,9 @@ class DomainBlock < ApplicationRecord
|
||||||
return false if other_block.silence? && noop?
|
return false if other_block.silence? && noop?
|
||||||
(reject_media || !other_block.reject_media) && (reject_reports || !other_block.reject_reports)
|
(reject_media || !other_block.reject_media) && (reject_reports || !other_block.reject_reports)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def affected_accounts_count
|
||||||
|
scope = suspend? ? accounts.where(suspended_at: created_at) : accounts.where(silenced_at: created_at)
|
||||||
|
scope.count
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -87,8 +87,8 @@ class Status < ApplicationRecord
|
||||||
scope :without_reblogs, -> { where('statuses.reblog_of_id IS NULL') }
|
scope :without_reblogs, -> { where('statuses.reblog_of_id IS NULL') }
|
||||||
scope :with_public_visibility, -> { where(visibility: :public) }
|
scope :with_public_visibility, -> { where(visibility: :public) }
|
||||||
scope :tagged_with, ->(tag) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag }) }
|
scope :tagged_with, ->(tag) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag }) }
|
||||||
scope :excluding_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced: false }) }
|
scope :excluding_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced_at: nil }) }
|
||||||
scope :including_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced: true }) }
|
scope :including_silenced_accounts, -> { left_outer_joins(:account).where.not(accounts: { silenced_at: nil }) }
|
||||||
scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) }
|
scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) }
|
||||||
scope :not_domain_blocked_by_account, ->(account) { account.excluded_from_timeline_domains.blank? ? left_outer_joins(:account) : left_outer_joins(:account).where('accounts.domain IS NULL OR accounts.domain NOT IN (?)', account.excluded_from_timeline_domains) }
|
scope :not_domain_blocked_by_account, ->(account) { account.excluded_from_timeline_domains.blank? ? left_outer_joins(:account) : left_outer_joins(:account).where('accounts.domain IS NULL OR accounts.domain NOT IN (?)', account.excluded_from_timeline_domains) }
|
||||||
scope :tagged_with_all, ->(tags) {
|
scope :tagged_with_all, ->(tags) {
|
||||||
|
|
|
@ -88,7 +88,7 @@ class User < ApplicationRecord
|
||||||
scope :confirmed, -> { where.not(confirmed_at: nil) }
|
scope :confirmed, -> { where.not(confirmed_at: nil) }
|
||||||
scope :enabled, -> { where(disabled: false) }
|
scope :enabled, -> { where(disabled: false) }
|
||||||
scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) }
|
scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) }
|
||||||
scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where(accounts: { suspended: false }) }
|
scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where.not(accounts: { suspended_at: nil }) }
|
||||||
scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) }
|
scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) }
|
||||||
scope :emailable, -> { confirmed.enabled.joins(:account).merge(Account.searchable) }
|
scope :emailable, -> { confirmed.enabled.joins(:account).merge(Account.searchable) }
|
||||||
|
|
||||||
|
|
|
@ -50,12 +50,12 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||||
|
|
||||||
def create_account
|
def create_account
|
||||||
@account = Account.new
|
@account = Account.new
|
||||||
@account.protocol = :activitypub
|
@account.protocol = :activitypub
|
||||||
@account.username = @username
|
@account.username = @username
|
||||||
@account.domain = @domain
|
@account.domain = @domain
|
||||||
@account.suspended = true if auto_suspend?
|
@account.private_key = nil
|
||||||
@account.silenced = true if auto_silence?
|
@account.suspended_at = domain_block.created_at if auto_suspend?
|
||||||
@account.private_key = nil
|
@account.silenced_at = domain_block.created_at if auto_silence?
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_account
|
def update_account
|
||||||
|
|
|
@ -29,7 +29,7 @@ class BlockDomainService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def silence_accounts!
|
def silence_accounts!
|
||||||
blocked_domain_accounts.in_batches.update_all(silenced: true)
|
blocked_domain_accounts.without_silenced.in_batches.update_all(silenced_at: @domain_block.created_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
def clear_media!
|
def clear_media!
|
||||||
|
@ -43,9 +43,9 @@ class BlockDomainService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def suspend_accounts!
|
def suspend_accounts!
|
||||||
blocked_domain_accounts.where(suspended: false).reorder(nil).find_each do |account|
|
blocked_domain_accounts.without_suspended.reorder(nil).find_each do |account|
|
||||||
UnsubscribeService.new.call(account) if account.subscribed?
|
UnsubscribeService.new.call(account) if account.subscribed?
|
||||||
SuspendAccountService.new.call(account)
|
SuspendAccountService.new.call(account, suspended_at: @domain_block.created_at)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ class PostStatusService < BaseService
|
||||||
@text = @media.find(&:video?) ? '📹' : '🖼' if @media.size > 0
|
@text = @media.find(&:video?) ? '📹' : '🖼' if @media.size > 0
|
||||||
end
|
end
|
||||||
@visibility = @options[:visibility] || @account.user&.setting_default_privacy
|
@visibility = @options[:visibility] || @account.user&.setting_default_privacy
|
||||||
@visibility = :unlisted if @visibility == :public && @account.silenced
|
@visibility = :unlisted if @visibility == :public && @account.silenced?
|
||||||
@scheduled_at = @options[:scheduled_at]&.to_datetime
|
@scheduled_at = @options[:scheduled_at]&.to_datetime
|
||||||
@scheduled_at = nil if scheduled_in_the_past?
|
@scheduled_at = nil if scheduled_in_the_past?
|
||||||
rescue ArgumentError
|
rescue ArgumentError
|
||||||
|
|
|
@ -25,7 +25,7 @@ class ProcessMentionsService < BaseService
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
next match if mention_undeliverable?(mentioned_account) || mentioned_account&.suspended
|
next match if mention_undeliverable?(mentioned_account) || mentioned_account&.suspended?
|
||||||
|
|
||||||
mentions << mentioned_account.mentions.where(status: status).first_or_create(status: status)
|
mentions << mentioned_account.mentions.where(status: status).first_or_create(status: status)
|
||||||
|
|
||||||
|
|
|
@ -119,9 +119,9 @@ class ResolveAccountService < BaseService
|
||||||
Rails.logger.debug "Creating new remote account for #{@username}@#{@domain}"
|
Rails.logger.debug "Creating new remote account for #{@username}@#{@domain}"
|
||||||
|
|
||||||
@account = Account.new(username: @username, domain: @domain)
|
@account = Account.new(username: @username, domain: @domain)
|
||||||
@account.suspended = true if auto_suspend?
|
@account.suspended_at = domain_block.created_at if auto_suspend?
|
||||||
@account.silenced = true if auto_silence?
|
@account.silenced_at = domain_block.created_at if auto_silence?
|
||||||
@account.private_key = nil
|
@account.private_key = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_account
|
def update_account
|
||||||
|
|
|
@ -43,7 +43,7 @@ class SubscribeService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def some_local_account
|
def some_local_account
|
||||||
@some_local_account ||= Account.local.where(suspended: false).first
|
@some_local_account ||= Account.local.without_suspended.first
|
||||||
end
|
end
|
||||||
|
|
||||||
# Any response in the 3xx or 4xx range, except for 429 (rate limit)
|
# Any response in the 3xx or 4xx range, except for 429 (rate limit)
|
||||||
|
|
|
@ -88,8 +88,8 @@ class SuspendAccountService < BaseService
|
||||||
|
|
||||||
return if @options[:destroy]
|
return if @options[:destroy]
|
||||||
|
|
||||||
@account.silenced = false
|
@account.silenced_at = nil
|
||||||
@account.suspended = true
|
@account.suspended_at = @options[:suspended_at] || Time.now.utc
|
||||||
@account.locked = false
|
@account.locked = false
|
||||||
@account.display_name = ''
|
@account.display_name = ''
|
||||||
@account.note = ''
|
@account.note = ''
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
class UnblockDomainService < BaseService
|
class UnblockDomainService < BaseService
|
||||||
attr_accessor :domain_block
|
attr_accessor :domain_block
|
||||||
|
|
||||||
def call(domain_block, retroactive)
|
def call(domain_block)
|
||||||
@domain_block = domain_block
|
@domain_block = domain_block
|
||||||
process_retroactive_updates if retroactive
|
process_retroactive_updates
|
||||||
domain_block.destroy
|
domain_block.destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -14,14 +14,19 @@ class UnblockDomainService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def blocked_accounts
|
def blocked_accounts
|
||||||
Account.where(domain: domain_block.domain)
|
scope = Account.where(domain: domain_block.domain)
|
||||||
|
if domain_block.silence?
|
||||||
|
scope.where(silenced_at: @domain_block.created_at)
|
||||||
|
else
|
||||||
|
scope.where(suspended_at: @domain_block.created_at)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_options
|
def update_options
|
||||||
{ domain_block_impact => false }
|
{ domain_block_impact => nil }
|
||||||
end
|
end
|
||||||
|
|
||||||
def domain_block_impact
|
def domain_block_impact
|
||||||
domain_block.silence? ? :silenced : :suspended
|
domain_block.silence? ? :silenced_at : :suspended_at
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,18 +3,11 @@
|
||||||
|
|
||||||
= simple_form_for @domain_block, url: admin_domain_block_path(@domain_block), method: :delete do |f|
|
= simple_form_for @domain_block, url: admin_domain_block_path(@domain_block), method: :delete do |f|
|
||||||
|
|
||||||
- if (@domain_block.noop?)
|
- unless (@domain_block.noop?)
|
||||||
= f.input :retroactive,
|
%p= t(".retroactive.#{@domain_block.severity}")
|
||||||
as: :hidden,
|
%p.hint= t(:affected_accounts,
|
||||||
input_html: { :value => "0" }
|
scope: [:admin, :domain_blocks, :show],
|
||||||
- else
|
count: @domain_block.affected_accounts_count)
|
||||||
= f.input :retroactive,
|
|
||||||
as: :boolean,
|
|
||||||
wrapper: :with_label,
|
|
||||||
label: t(".retroactive.#{@domain_block.severity}"),
|
|
||||||
hint: t(:affected_accounts,
|
|
||||||
scope: [:admin, :domain_blocks, :show],
|
|
||||||
count: @domain_block.accounts_count)
|
|
||||||
|
|
||||||
.actions
|
.actions
|
||||||
= f.button :button, t('.undo'), type: :submit
|
= f.button :button, t('.undo'), type: :submit
|
||||||
|
|
|
@ -294,8 +294,8 @@ en:
|
||||||
one: One account in the database affected
|
one: One account in the database affected
|
||||||
other: "%{count} accounts in the database affected"
|
other: "%{count} accounts in the database affected"
|
||||||
retroactive:
|
retroactive:
|
||||||
silence: Unsilence all existing accounts from this domain
|
silence: Unsilence existing affected accounts from this domain
|
||||||
suspend: Unsuspend all existing accounts from this domain
|
suspend: Unsuspend existing affected accounts from this domain
|
||||||
title: Undo domain block for %{domain}
|
title: Undo domain block for %{domain}
|
||||||
undo: Undo
|
undo: Undo
|
||||||
undo: Undo domain block
|
undo: Undo domain block
|
||||||
|
|
|
@ -128,7 +128,7 @@ fr:
|
||||||
follow: Envoyer un courriel lorsque quelqu’un me suit
|
follow: Envoyer un courriel lorsque quelqu’un me suit
|
||||||
follow_request: Envoyer un courriel lorsque quelqu’un demande à me suivre
|
follow_request: Envoyer un courriel lorsque quelqu’un demande à me suivre
|
||||||
mention: Envoyer un courriel lorsque quelqu’un me mentionne
|
mention: Envoyer un courriel lorsque quelqu’un me mentionne
|
||||||
pending_account: Envoyer un courriel lorsqu'un nouveau compte est en attente d'approbation
|
pending_account: Envoyer un courriel lorsqu’un nouveau compte est en attente d’approbation
|
||||||
reblog: Envoyer un courriel lorsque quelqu’un partage mes statuts
|
reblog: Envoyer un courriel lorsque quelqu’un partage mes statuts
|
||||||
report: Envoyer un courriel lorsqu’un nouveau rapport est soumis
|
report: Envoyer un courriel lorsqu’un nouveau rapport est soumis
|
||||||
'no': Non
|
'no': Non
|
||||||
|
|
|
@ -28,12 +28,12 @@ sk:
|
||||||
scopes: Ktoré API budú povolené aplikácii pre prístup. Ak vyberieš vrcholný stupeň, nemusíš už potom vyberať po jednom.
|
scopes: Ktoré API budú povolené aplikácii pre prístup. Ak vyberieš vrcholný stupeň, nemusíš už potom vyberať po jednom.
|
||||||
setting_aggregate_reblogs: Nezobrazuj nové vyzdvihnutia pre príspevky, ktoré už boli len nedávno povýšené (týka sa iba nanovo získaných povýšení)
|
setting_aggregate_reblogs: Nezobrazuj nové vyzdvihnutia pre príspevky, ktoré už boli len nedávno povýšené (týka sa iba nanovo získaných povýšení)
|
||||||
setting_default_language: Jazyk tvojích príspevkov môže byť zistený automaticky, ale nieje to vždy presné
|
setting_default_language: Jazyk tvojích príspevkov môže byť zistený automaticky, ale nieje to vždy presné
|
||||||
setting_display_media_default: Skryť médiá označené ako citlivé
|
setting_display_media_default: Skry médiá označené ako citlivé
|
||||||
setting_display_media_hide_all: Vždy ukryť všetky médiá
|
setting_display_media_hide_all: Vždy ukry všetky médiá
|
||||||
setting_display_media_show_all: Stále ukazuj médiá označené ako citlivé
|
setting_display_media_show_all: Stále zobrazuj médiá označené ako citlivé
|
||||||
setting_hide_network: Koho následuješ, a kto následuje teba nebude zobrazené na tvojom profile
|
setting_hide_network: Koho následuješ, a kto následuje teba, nebude zobrazené na tvojom profile
|
||||||
setting_noindex: Ovplyvňuje verejný profil a stránky s príspevkami
|
setting_noindex: Ovplyvňuje verejný profil a stránky s príspevkami
|
||||||
setting_show_application: Aplikácia, ktorú používaš na písanie príspevkov, bude zobrazená v detailnom náhľade jednotlivých tvojích príspevkov
|
setting_show_application: Aplikácia, ktorú používaš na písanie príspevkov, bude zobrazená v podrobnom náhľade jednotlivých tvojích príspevkov
|
||||||
setting_theme: Ovplyvňuje ako Mastodon vyzerá pri prihlásení z hociakého zariadenia.
|
setting_theme: Ovplyvňuje ako Mastodon vyzerá pri prihlásení z hociakého zariadenia.
|
||||||
username: Tvoja prezývka bude unikátna pre server %{domain}
|
username: Tvoja prezývka bude unikátna pre server %{domain}
|
||||||
whole_word: Ak je kľúčové slovo, alebo fráza poskladaná iba s písmen a čísel, bude použité iba ak sa zhoduje s celým výrazom
|
whole_word: Ak je kľúčové slovo, alebo fráza poskladaná iba s písmen a čísel, bude použité iba ak sa zhoduje s celým výrazom
|
||||||
|
@ -41,6 +41,8 @@ sk:
|
||||||
name: 'Možno by si chcel/a použiť niektoré z týchto:'
|
name: 'Možno by si chcel/a použiť niektoré z týchto:'
|
||||||
imports:
|
imports:
|
||||||
data: CSV súbor vyexportovaný z iného Mastodon serveru
|
data: CSV súbor vyexportovaný z iného Mastodon serveru
|
||||||
|
invite_request:
|
||||||
|
text: Toto pomôže s vyhodnocovaním tvojej žiadosti
|
||||||
sessions:
|
sessions:
|
||||||
otp: 'Napíš sem dvoj-faktorový kód z telefónu, alebo použi jeden z tvojích obnovovacích kódov:'
|
otp: 'Napíš sem dvoj-faktorový kód z telefónu, alebo použi jeden z tvojích obnovovacích kódov:'
|
||||||
user:
|
user:
|
||||||
|
@ -59,7 +61,7 @@ sk:
|
||||||
types:
|
types:
|
||||||
disable: Deaktivuj
|
disable: Deaktivuj
|
||||||
none: Neurob nič
|
none: Neurob nič
|
||||||
silence: Utíšenie
|
silence: Utíš
|
||||||
suspend: Vylúč a nenávratne vymaž dáta na účte
|
suspend: Vylúč a nenávratne vymaž dáta na účte
|
||||||
warning_preset_id: Použi varovnú predlohu
|
warning_preset_id: Použi varovnú predlohu
|
||||||
defaults:
|
defaults:
|
||||||
|
@ -119,13 +121,14 @@ sk:
|
||||||
must_be_following: Blokuj oboznámenia od ľudí, ktorých nesledujem
|
must_be_following: Blokuj oboznámenia od ľudí, ktorých nesledujem
|
||||||
must_be_following_dm: Blokuj súkromné správy od ľudí ktorých nesledujem
|
must_be_following_dm: Blokuj súkromné správy od ľudí ktorých nesledujem
|
||||||
notification_emails:
|
notification_emails:
|
||||||
digest: Posielaj súhrnné emaily
|
digest: Zasielať súhrnné emaily
|
||||||
favourite: Poslať email ak si niekto obľúbi tvoj príspevok
|
favourite: Zaslať email, ak si niekto obľúbi tvoj príspevok
|
||||||
follow: Poslať email, ak ťa niekto začne následovať
|
follow: Zaslať email, ak ťa niekto začne následovať
|
||||||
follow_request: Zaslať email ak ti niekto pošle žiadosť o sledovanie
|
follow_request: Zaslať email, ak ti niekto pošle žiadosť o sledovanie
|
||||||
mention: Poslať email ak ťa niekto spomenie v svojom príspevku
|
mention: Zaslať email, ak ťa niekto spomenie vo svojom príspevku
|
||||||
reblog: Poslať email ak niekto re-tootne tvoj príspevok
|
pending_account: Zaslať email, ak treba prehodnotiť nový účet
|
||||||
report: Poslať e-mail ak niekto dodá nové hlásenie
|
reblog: Zaslať email, ak niekto re-tootne tvoj príspevok
|
||||||
|
report: Zaslať email, ak niekto podá nové nahlásenie
|
||||||
'no': Nie
|
'no': Nie
|
||||||
required:
|
required:
|
||||||
mark: "*"
|
mark: "*"
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
class AddSilencedAtSuspendedAtToAccounts < ActiveRecord::Migration[5.2]
|
||||||
|
class Account < ApplicationRecord
|
||||||
|
# Dummy class, to make migration possible across version changes
|
||||||
|
end
|
||||||
|
|
||||||
|
class DomainBlock < ApplicationRecord
|
||||||
|
# Dummy class, to make migration possible across version changes
|
||||||
|
enum severity: [:silence, :suspend, :noop]
|
||||||
|
|
||||||
|
has_many :accounts, foreign_key: :domain, primary_key: :domain
|
||||||
|
end
|
||||||
|
|
||||||
|
def up
|
||||||
|
add_column :accounts, :silenced_at, :datetime
|
||||||
|
add_column :accounts, :suspended_at, :datetime
|
||||||
|
|
||||||
|
# Record suspend date of blocks and silences for users whose limitations match
|
||||||
|
# a domain block
|
||||||
|
DomainBlock.where(severity: [:silence, :suspend]).find_each do |block|
|
||||||
|
scope = block.accounts
|
||||||
|
if block.suspend?
|
||||||
|
block.accounts.where(suspended: true).in_batches.update_all(suspended_at: block.created_at)
|
||||||
|
else
|
||||||
|
block.accounts.where(silenced: true).in_batches.update_all(silenced_at: block.created_at)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Set dates for accounts which have limitations not related to a domain block
|
||||||
|
Account.where(suspended: true, suspended_at: nil).in_batches.update_all(suspended_at: Time.now.utc)
|
||||||
|
Account.where(silenced: true, silenced_at: nil).in_batches.update_all(silenced_at: Time.now.utc)
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
# Block or silence accounts that have a date set
|
||||||
|
Account.where(suspended: false).where.not(suspended_at: nil).in_batches.update_all(suspended: true)
|
||||||
|
Account.where(silenced: false).where.not(silenced_at: nil).in_batches.update_all(silenced: true)
|
||||||
|
|
||||||
|
remove_column :accounts, :silenced_at
|
||||||
|
remove_column :accounts, :suspended_at
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,45 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class RemoveSuspendedSilencedAccountFields < ActiveRecord::Migration[5.2]
|
||||||
|
class Account < ApplicationRecord
|
||||||
|
# Dummy class, to make migration possible across version changes
|
||||||
|
end
|
||||||
|
|
||||||
|
class DomainBlock < ApplicationRecord
|
||||||
|
# Dummy class, to make migration possible across version changes
|
||||||
|
enum severity: [:silence, :suspend, :noop]
|
||||||
|
|
||||||
|
has_many :accounts, foreign_key: :domain, primary_key: :domain
|
||||||
|
end
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
# Record suspend date of blocks and silences for users whose limitations match
|
||||||
|
# a domain block
|
||||||
|
DomainBlock.where(severity: [:silence, :suspend]).find_each do |block|
|
||||||
|
scope = block.accounts
|
||||||
|
if block.suspend?
|
||||||
|
block.accounts.where(suspended: true).in_batches.update_all(suspended_at: block.created_at)
|
||||||
|
else
|
||||||
|
block.accounts.where(silenced: true).in_batches.update_all(silenced_at: block.created_at)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Set dates for accounts which have limitations not related to a domain block
|
||||||
|
Account.where(suspended: true, suspended_at: nil).in_batches.update_all(suspended_at: Time.now.utc)
|
||||||
|
Account.where(silenced: true, silenced_at: nil).in_batches.update_all(silenced_at: Time.now.utc)
|
||||||
|
|
||||||
|
safety_assured do
|
||||||
|
remove_column :accounts, :suspended, :boolean, null: false, default: false
|
||||||
|
remove_column :accounts, :silenced, :boolean, null: false, default: false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
safety_assured do
|
||||||
|
add_column :accounts, :suspended, :boolean, null: false, default: false
|
||||||
|
add_column :accounts, :silenced, :boolean, null: false, default: false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2019_05_09_164208) do
|
ActiveRecord::Schema.define(version: 2019_05_11_152737) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -131,8 +131,6 @@ ActiveRecord::Schema.define(version: 2019_05_09_164208) do
|
||||||
t.datetime "header_updated_at"
|
t.datetime "header_updated_at"
|
||||||
t.string "avatar_remote_url"
|
t.string "avatar_remote_url"
|
||||||
t.datetime "subscription_expires_at"
|
t.datetime "subscription_expires_at"
|
||||||
t.boolean "silenced", default: false, null: false
|
|
||||||
t.boolean "suspended", default: false, null: false
|
|
||||||
t.boolean "locked", default: false, null: false
|
t.boolean "locked", default: false, null: false
|
||||||
t.string "header_remote_url", default: "", null: false
|
t.string "header_remote_url", default: "", null: false
|
||||||
t.datetime "last_webfingered_at"
|
t.datetime "last_webfingered_at"
|
||||||
|
@ -148,6 +146,8 @@ ActiveRecord::Schema.define(version: 2019_05_09_164208) do
|
||||||
t.string "actor_type"
|
t.string "actor_type"
|
||||||
t.boolean "discoverable"
|
t.boolean "discoverable"
|
||||||
t.string "also_known_as", array: true
|
t.string "also_known_as", array: true
|
||||||
|
t.datetime "silenced_at"
|
||||||
|
t.datetime "suspended_at"
|
||||||
t.index "(((setweight(to_tsvector('simple'::regconfig, (display_name)::text), 'A'::\"char\") || setweight(to_tsvector('simple'::regconfig, (username)::text), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (COALESCE(domain, ''::character varying))::text), 'C'::\"char\")))", name: "search_index", using: :gin
|
t.index "(((setweight(to_tsvector('simple'::regconfig, (display_name)::text), 'A'::\"char\") || setweight(to_tsvector('simple'::regconfig, (username)::text), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (COALESCE(domain, ''::character varying))::text), 'C'::\"char\")))", name: "search_index", using: :gin
|
||||||
t.index "lower((username)::text), lower((domain)::text)", name: "index_accounts_on_username_and_domain_lower", unique: true
|
t.index "lower((username)::text), lower((domain)::text)", name: "index_accounts_on_username_and_domain_lower", unique: true
|
||||||
t.index ["moved_to_account_id"], name: "index_accounts_on_moved_to_account_id"
|
t.index ["moved_to_account_id"], name: "index_accounts_on_moved_to_account_id"
|
||||||
|
|
|
@ -106,7 +106,7 @@ module Mastodon
|
||||||
[json, account.id, inbox_url]
|
[json, account.id, inbox_url]
|
||||||
end
|
end
|
||||||
|
|
||||||
account.update_column(:suspended, true)
|
account.suspend!
|
||||||
end
|
end
|
||||||
|
|
||||||
processed += 1
|
processed += 1
|
||||||
|
|
|
@ -87,8 +87,8 @@ module Mastodon
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
account.suspended = false
|
account.suspended_at = nil
|
||||||
user.account = account
|
user.account = account
|
||||||
|
|
||||||
if user.save
|
if user.save
|
||||||
if options[:confirmed]
|
if options[:confirmed]
|
||||||
|
|
|
@ -63,9 +63,9 @@ RSpec.describe Admin::DomainBlocksController, type: :controller do
|
||||||
service = double(call: true)
|
service = double(call: true)
|
||||||
allow(UnblockDomainService).to receive(:new).and_return(service)
|
allow(UnblockDomainService).to receive(:new).and_return(service)
|
||||||
domain_block = Fabricate(:domain_block)
|
domain_block = Fabricate(:domain_block)
|
||||||
delete :destroy, params: { id: domain_block.id, domain_block: { retroactive: '1' } }
|
delete :destroy, params: { id: domain_block.id }
|
||||||
|
|
||||||
expect(service).to have_received(:call).with(domain_block, true)
|
expect(service).to have_received(:call).with(domain_block)
|
||||||
expect(flash[:notice]).to eq I18n.t('admin.domain_blocks.destroyed_msg')
|
expect(flash[:notice]).to eq I18n.t('admin.domain_blocks.destroyed_msg')
|
||||||
expect(response).to redirect_to(admin_instances_path(limited: '1'))
|
expect(response).to redirect_to(admin_instances_path(limited: '1'))
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,8 +3,11 @@ public_key = keypair.public_key.to_pem
|
||||||
private_key = keypair.to_pem
|
private_key = keypair.to_pem
|
||||||
|
|
||||||
Fabricator(:account) do
|
Fabricator(:account) do
|
||||||
|
transient :suspended, :silenced
|
||||||
username { sequence(:username) { |i| "#{Faker::Internet.user_name(nil, %w(_))}#{i}" } }
|
username { sequence(:username) { |i| "#{Faker::Internet.user_name(nil, %w(_))}#{i}" } }
|
||||||
last_webfingered_at { Time.now.utc }
|
last_webfingered_at { Time.now.utc }
|
||||||
public_key { public_key }
|
public_key { public_key }
|
||||||
private_key { private_key }
|
private_key { private_key }
|
||||||
|
suspended_at { |attrs| attrs[:suspended] ? Time.now.utc : nil }
|
||||||
|
silenced_at { |attrs| attrs[:silenced] ? Time.now.utc : nil }
|
||||||
end
|
end
|
||||||
|
|
|
@ -175,13 +175,13 @@ RSpec.describe FeedManager do
|
||||||
|
|
||||||
it 'returns true for status by silenced account who recipient is not following' do
|
it 'returns true for status by silenced account who recipient is not following' do
|
||||||
status = Fabricate(:status, text: 'Hello world', account: alice)
|
status = Fabricate(:status, text: 'Hello world', account: alice)
|
||||||
alice.update(silenced: true)
|
alice.silence!
|
||||||
expect(FeedManager.instance.filter?(:mentions, status, bob.id)).to be true
|
expect(FeedManager.instance.filter?(:mentions, status, bob.id)).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns false for status by followed silenced account' do
|
it 'returns false for status by followed silenced account' do
|
||||||
status = Fabricate(:status, text: 'Hello world', account: alice)
|
status = Fabricate(:status, text: 'Hello world', account: alice)
|
||||||
alice.update(silenced: true)
|
alice.silence!
|
||||||
bob.follow!(alice)
|
bob.follow!(alice)
|
||||||
expect(FeedManager.instance.filter?(:mentions, status, bob.id)).to be false
|
expect(FeedManager.instance.filter?(:mentions, status, bob.id)).to be false
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,7 +15,7 @@ describe StatusFilter do
|
||||||
|
|
||||||
context 'when status account is silenced' do
|
context 'when status account is silenced' do
|
||||||
before do
|
before do
|
||||||
status.account.update(silenced: true)
|
status.account.silence!
|
||||||
end
|
end
|
||||||
|
|
||||||
it { is_expected.to be_filtered }
|
it { is_expected.to be_filtered }
|
||||||
|
@ -65,7 +65,7 @@ describe StatusFilter do
|
||||||
|
|
||||||
context 'when status account is silenced' do
|
context 'when status account is silenced' do
|
||||||
before do
|
before do
|
||||||
status.account.update(silenced: true)
|
status.account.silence!
|
||||||
end
|
end
|
||||||
|
|
||||||
it { is_expected.to be_filtered }
|
it { is_expected.to be_filtered }
|
||||||
|
|
|
@ -35,7 +35,7 @@ describe StatusThreadingConcern do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not return conversation history from silenced and not followed users' do
|
it 'does not return conversation history from silenced and not followed users' do
|
||||||
jeff.update(silenced: true)
|
jeff.silence!
|
||||||
expect(reply3.ancestors(4, viewer)).to_not include(reply1)
|
expect(reply3.ancestors(4, viewer)).to_not include(reply1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ describe StatusThreadingConcern do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not return replies from silenced and not followed users' do
|
it 'does not return replies from silenced and not followed users' do
|
||||||
jeff.update(silenced: true)
|
jeff.silence!
|
||||||
expect(status.descendants(4, viewer)).to_not include(reply3)
|
expect(status.descendants(4, viewer)).to_not include(reply3)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,14 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe BlockDomainService, type: :service do
|
RSpec.describe BlockDomainService, type: :service do
|
||||||
let(:bad_account) { Fabricate(:account, username: 'badguy666', domain: 'evil.org') }
|
let!(:bad_account) { Fabricate(:account, username: 'badguy666', domain: 'evil.org') }
|
||||||
let(:bad_status1) { Fabricate(:status, account: bad_account, text: 'You suck') }
|
let!(:bad_status1) { Fabricate(:status, account: bad_account, text: 'You suck') }
|
||||||
let(:bad_status2) { Fabricate(:status, account: bad_account, text: 'Hahaha') }
|
let!(:bad_status2) { Fabricate(:status, account: bad_account, text: 'Hahaha') }
|
||||||
let(:bad_attachment) { Fabricate(:media_attachment, account: bad_account, status: bad_status2, file: attachment_fixture('attachment.jpg')) }
|
let!(:bad_attachment) { Fabricate(:media_attachment, account: bad_account, status: bad_status2, file: attachment_fixture('attachment.jpg')) }
|
||||||
|
let!(:already_banned_account) { Fabricate(:account, username: 'badguy', domain: 'evil.org', suspended: true, silenced: true) }
|
||||||
|
|
||||||
subject { BlockDomainService.new }
|
subject { BlockDomainService.new }
|
||||||
|
|
||||||
before do
|
|
||||||
bad_account
|
|
||||||
bad_status1
|
|
||||||
bad_status2
|
|
||||||
bad_attachment
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'for a suspension' do
|
describe 'for a suspension' do
|
||||||
before do
|
before do
|
||||||
subject.call(DomainBlock.create!(domain: 'evil.org', severity: :suspend))
|
subject.call(DomainBlock.create!(domain: 'evil.org', severity: :suspend))
|
||||||
|
@ -28,6 +22,18 @@ RSpec.describe BlockDomainService, type: :service do
|
||||||
expect(Account.find_remote('badguy666', 'evil.org').suspended?).to be true
|
expect(Account.find_remote('badguy666', 'evil.org').suspended?).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'records suspension date appropriately' do
|
||||||
|
expect(Account.find_remote('badguy666', 'evil.org').suspended_at).to eq DomainBlock.find_by(domain: 'evil.org').created_at
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'keeps already-banned accounts banned' do
|
||||||
|
expect(Account.find_remote('badguy', 'evil.org').suspended?).to be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not overwrite suspension date of already-banned accounts' do
|
||||||
|
expect(Account.find_remote('badguy', 'evil.org').suspended_at).to_not eq DomainBlock.find_by(domain: 'evil.org').created_at
|
||||||
|
end
|
||||||
|
|
||||||
it 'removes the remote accounts\'s statuses and media attachments' do
|
it 'removes the remote accounts\'s statuses and media attachments' do
|
||||||
expect { bad_status1.reload }.to raise_exception ActiveRecord::RecordNotFound
|
expect { bad_status1.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||||
expect { bad_status2.reload }.to raise_exception ActiveRecord::RecordNotFound
|
expect { bad_status2.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||||
|
@ -48,6 +54,18 @@ RSpec.describe BlockDomainService, type: :service do
|
||||||
expect(Account.find_remote('badguy666', 'evil.org').silenced?).to be true
|
expect(Account.find_remote('badguy666', 'evil.org').silenced?).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'records suspension date appropriately' do
|
||||||
|
expect(Account.find_remote('badguy666', 'evil.org').silenced_at).to eq DomainBlock.find_by(domain: 'evil.org').created_at
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'keeps already-banned accounts banned' do
|
||||||
|
expect(Account.find_remote('badguy', 'evil.org').silenced?).to be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not overwrite suspension date of already-banned accounts' do
|
||||||
|
expect(Account.find_remote('badguy', 'evil.org').silenced_at).to_not eq DomainBlock.find_by(domain: 'evil.org').created_at
|
||||||
|
end
|
||||||
|
|
||||||
it 'leaves the domains status and attachements, but clears media' do
|
it 'leaves the domains status and attachements, but clears media' do
|
||||||
expect { bad_status1.reload }.not_to raise_error
|
expect { bad_status1.reload }.not_to raise_error
|
||||||
expect { bad_status2.reload }.not_to raise_error
|
expect { bad_status2.reload }.not_to raise_error
|
||||||
|
|
|
@ -39,12 +39,12 @@ RSpec.describe NotifyService, type: :service do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not notify when sender is silenced and not followed' do
|
it 'does not notify when sender is silenced and not followed' do
|
||||||
sender.update(silenced: true)
|
sender.silence!
|
||||||
is_expected.to_not change(Notification, :count)
|
is_expected.to_not change(Notification, :count)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not notify when recipient is suspended' do
|
it 'does not notify when recipient is suspended' do
|
||||||
recipient.update(suspended: true)
|
recipient.suspend!
|
||||||
is_expected.to_not change(Notification, :count)
|
is_expected.to_not change(Notification, :count)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,36 +7,33 @@ describe UnblockDomainService, type: :service do
|
||||||
|
|
||||||
describe 'call' do
|
describe 'call' do
|
||||||
before do
|
before do
|
||||||
@silenced = Fabricate(:account, domain: 'example.com', silenced: true)
|
@independently_suspended = Fabricate(:account, domain: 'example.com', suspended_at: 1.hour.ago)
|
||||||
@suspended = Fabricate(:account, domain: 'example.com', suspended: true)
|
@independently_silenced = Fabricate(:account, domain: 'example.com', silenced_at: 1.hour.ago)
|
||||||
@domain_block = Fabricate(:domain_block, domain: 'example.com')
|
@domain_block = Fabricate(:domain_block, domain: 'example.com')
|
||||||
|
@silenced = Fabricate(:account, domain: 'example.com', silenced_at: @domain_block.created_at)
|
||||||
|
@suspended = Fabricate(:account, domain: 'example.com', suspended_at: @domain_block.created_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'without retroactive' do
|
it 'unsilences accounts and removes block' do
|
||||||
it 'removes the domain block' do
|
@domain_block.update(severity: :silence)
|
||||||
subject.call(@domain_block, false)
|
|
||||||
expect_deleted_domain_block
|
subject.call(@domain_block)
|
||||||
end
|
expect_deleted_domain_block
|
||||||
|
expect(@silenced.reload.silenced?).to be false
|
||||||
|
expect(@suspended.reload.suspended?).to be true
|
||||||
|
expect(@independently_suspended.reload.suspended?).to be true
|
||||||
|
expect(@independently_silenced.reload.silenced?).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with retroactive' do
|
it 'unsuspends accounts and removes block' do
|
||||||
it 'unsilences accounts and removes block' do
|
@domain_block.update(severity: :suspend)
|
||||||
@domain_block.update(severity: :silence)
|
|
||||||
|
|
||||||
subject.call(@domain_block, true)
|
subject.call(@domain_block)
|
||||||
expect_deleted_domain_block
|
expect_deleted_domain_block
|
||||||
expect(@silenced.reload.silenced).to be false
|
expect(@suspended.reload.suspended?).to be false
|
||||||
expect(@suspended.reload.suspended).to be true
|
expect(@silenced.reload.silenced?).to be true
|
||||||
end
|
expect(@independently_suspended.reload.suspended?).to be true
|
||||||
|
expect(@independently_silenced.reload.silenced?).to be true
|
||||||
it 'unsuspends accounts and removes block' do
|
|
||||||
@domain_block.update(severity: :suspend)
|
|
||||||
|
|
||||||
subject.call(@domain_block, true)
|
|
||||||
expect_deleted_domain_block
|
|
||||||
expect(@suspended.reload.suspended).to be false
|
|
||||||
expect(@silenced.reload.silenced).to be true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue