Merge tag 'v2.9.2' into instance_only_statuses
This commit is contained in:
@ -28,8 +28,6 @@
|
||||
# header_updated_at :datetime
|
||||
# avatar_remote_url :string
|
||||
# subscription_expires_at :datetime
|
||||
# silenced :boolean default(FALSE), not null
|
||||
# suspended :boolean default(FALSE), not null
|
||||
# locked :boolean default(FALSE), not null
|
||||
# header_remote_url :string default(""), not null
|
||||
# last_webfingered_at :datetime
|
||||
@ -45,6 +43,8 @@
|
||||
# actor_type :string
|
||||
# discoverable :boolean
|
||||
# also_known_as :string is an Array
|
||||
# silenced_at :datetime
|
||||
# suspended_at :datetime
|
||||
#
|
||||
|
||||
class Account < ApplicationRecord
|
||||
@ -75,17 +75,17 @@ class Account < ApplicationRecord
|
||||
validates_with UniqueUsernameValidator, if: -> { local? && will_save_change_to_username? }
|
||||
validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? }
|
||||
validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? }
|
||||
validates :note, note_length: { maximum: 160 }, if: -> { local? && will_save_change_to_note? }
|
||||
validates :note, note_length: { maximum: 500 }, if: -> { local? && will_save_change_to_note? }
|
||||
validates :fields, length: { maximum: 4 }, if: -> { local? && will_save_change_to_fields? }
|
||||
|
||||
scope :remote, -> { where.not(domain: nil) }
|
||||
scope :local, -> { where(domain: nil) }
|
||||
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 :silenced, -> { where(silenced: true) }
|
||||
scope :suspended, -> { where(suspended: true) }
|
||||
scope :without_suspended, -> { where(suspended: false) }
|
||||
scope :without_silenced, -> { where(silenced: false) }
|
||||
scope :silenced, -> { where.not(silenced_at: nil) }
|
||||
scope :suspended, -> { where.not(suspended_at: nil) }
|
||||
scope :without_suspended, -> { where(suspended_at: nil) }
|
||||
scope :without_silenced, -> { where(silenced_at: nil) }
|
||||
scope :recent, -> { reorder(id: :desc) }
|
||||
scope :bots, -> { where(actor_type: %w(Application Service)) }
|
||||
scope :alphabetic, -> { order(domain: :asc, username: :asc) }
|
||||
@ -98,6 +98,7 @@ class Account < ApplicationRecord
|
||||
scope :tagged_with, ->(tag) { joins(:accounts_tags).where(accounts_tags: { tag_id: tag }) }
|
||||
scope :by_recent_status, -> { order(Arel.sql('(case when account_stats.last_status_at is null then 1 else 0 end) asc, account_stats.last_status_at desc')) }
|
||||
scope :popular, -> { order('account_stats.followers_count desc') }
|
||||
scope :by_domain_and_subdomains, ->(domain) { where(domain: domain).or(where(arel_table[:domain].matches('%.' + domain))) }
|
||||
|
||||
delegate :email,
|
||||
:unconfirmed_email,
|
||||
@ -106,6 +107,8 @@ class Account < ApplicationRecord
|
||||
:confirmed?,
|
||||
:approved?,
|
||||
:pending?,
|
||||
:disabled?,
|
||||
:role,
|
||||
:admin?,
|
||||
:moderator?,
|
||||
:staff?,
|
||||
@ -165,25 +168,35 @@ class Account < ApplicationRecord
|
||||
ResolveAccountService.new.call(acct)
|
||||
end
|
||||
|
||||
def silence!
|
||||
update!(silenced: true)
|
||||
def silenced?
|
||||
silenced_at.present?
|
||||
end
|
||||
|
||||
def silence!(date = nil)
|
||||
date ||= Time.now.utc
|
||||
update!(silenced_at: date)
|
||||
end
|
||||
|
||||
def unsilence!
|
||||
update!(silenced: false)
|
||||
update!(silenced_at: nil)
|
||||
end
|
||||
|
||||
def suspend!
|
||||
def suspended?
|
||||
suspended_at.present?
|
||||
end
|
||||
|
||||
def suspend!(date = nil)
|
||||
date ||= Time.now.utc
|
||||
transaction do
|
||||
user&.disable! if local?
|
||||
update!(suspended: true)
|
||||
update!(suspended_at: date)
|
||||
end
|
||||
end
|
||||
|
||||
def unsuspend!
|
||||
transaction do
|
||||
user&.enable! if local?
|
||||
update!(suspended: false)
|
||||
update!(suspended_at: nil)
|
||||
end
|
||||
end
|
||||
|
||||
@ -194,6 +207,10 @@ class Account < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def sign?
|
||||
true
|
||||
end
|
||||
|
||||
def keypair
|
||||
@keypair ||= OpenSSL::PKey::RSA.new(private_key || public_key)
|
||||
end
|
||||
@ -399,7 +416,7 @@ class Account < ApplicationRecord
|
||||
ts_rank_cd(#{textsearch}, #{query}, 32) AS rank
|
||||
FROM accounts
|
||||
WHERE #{query} @@ #{textsearch}
|
||||
AND accounts.suspended = false
|
||||
AND accounts.suspended_at IS NULL
|
||||
AND accounts.moved_to_account_id IS NULL
|
||||
ORDER BY rank DESC
|
||||
LIMIT ? OFFSET ?
|
||||
@ -427,7 +444,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 = ?)
|
||||
WHERE accounts.id IN (SELECT * FROM first_degree)
|
||||
AND #{query} @@ #{textsearch}
|
||||
AND accounts.suspended = false
|
||||
AND accounts.suspended_at IS NULL
|
||||
AND accounts.moved_to_account_id IS NULL
|
||||
GROUP BY accounts.id
|
||||
ORDER BY rank DESC
|
||||
@ -443,7 +460,7 @@ class Account < ApplicationRecord
|
||||
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 = ?)
|
||||
WHERE #{query} @@ #{textsearch}
|
||||
AND accounts.suspended = false
|
||||
AND accounts.suspended_at IS NULL
|
||||
AND accounts.moved_to_account_id IS NULL
|
||||
GROUP BY accounts.id
|
||||
ORDER BY rank DESC
|
||||
|
@ -37,6 +37,8 @@ class AccountFilter
|
||||
Account.without_suspended
|
||||
when 'pending'
|
||||
accounts_with_users.merge User.pending
|
||||
when 'disabled'
|
||||
accounts_with_users.merge User.disabled
|
||||
when 'silenced'
|
||||
Account.silenced
|
||||
when 'suspended'
|
||||
|
@ -13,7 +13,7 @@ module AccountFinderConcern
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
def find_local(username)
|
||||
|
@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'mime/types'
|
||||
require 'mime/types/columnar'
|
||||
|
||||
module Attachmentable
|
||||
extend ActiveSupport::Concern
|
||||
@ -10,10 +10,21 @@ module Attachmentable
|
||||
included do
|
||||
before_post_process :set_file_extensions
|
||||
before_post_process :check_image_dimensions
|
||||
before_post_process :set_file_content_type
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_file_content_type
|
||||
self.class.attachment_definitions.each_key do |attachment_name|
|
||||
attachment = send(attachment_name)
|
||||
|
||||
next if attachment.blank? || attachment.queued_for_write[:original].blank?
|
||||
|
||||
attachment.instance_write :content_type, calculated_content_type(attachment)
|
||||
end
|
||||
end
|
||||
|
||||
def set_file_extensions
|
||||
self.class.attachment_definitions.each_key do |attachment_name|
|
||||
attachment = send(attachment_name)
|
||||
@ -47,4 +58,10 @@ module Attachmentable
|
||||
|
||||
extension
|
||||
end
|
||||
|
||||
def calculated_content_type(attachment)
|
||||
Paperclip.run('file', '-b --mime :file', file: attachment.queued_for_write[:original].path).split(/[:;\s]+/).first.chomp
|
||||
rescue Terrapin::CommandLineError
|
||||
''
|
||||
end
|
||||
end
|
||||
|
@ -13,6 +13,20 @@ module UserRoles
|
||||
admin? || moderator?
|
||||
end
|
||||
|
||||
def role=(value)
|
||||
case value
|
||||
when 'admin'
|
||||
self.admin = true
|
||||
self.moderator = false
|
||||
when 'moderator'
|
||||
self.admin = false
|
||||
self.moderator = true
|
||||
else
|
||||
self.admin = false
|
||||
self.moderator = false
|
||||
end
|
||||
end
|
||||
|
||||
def role
|
||||
if admin?
|
||||
'admin'
|
||||
|
@ -39,6 +39,7 @@ class CustomEmoji < ApplicationRecord
|
||||
scope :local, -> { where(domain: nil) }
|
||||
scope :remote, -> { where.not(domain: nil) }
|
||||
scope :alphabetic, -> { order(domain: :asc, shortcode: :asc) }
|
||||
scope :by_domain_and_subdomains, ->(domain) { where(domain: domain).or(where(arel_table[:domain].matches('%.' + domain))) }
|
||||
|
||||
remotable_attachment :image, LIMIT
|
||||
|
||||
|
@ -17,8 +17,6 @@ class DomainBlock < ApplicationRecord
|
||||
|
||||
enum severity: [:silence, :suspend, :noop]
|
||||
|
||||
attr_accessor :retroactive
|
||||
|
||||
validates :domain, presence: true, uniqueness: true
|
||||
|
||||
has_many :accounts, foreign_key: :domain, primary_key: :domain
|
||||
@ -26,14 +24,46 @@ class DomainBlock < ApplicationRecord
|
||||
|
||||
scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) }
|
||||
|
||||
def self.blocked?(domain)
|
||||
where(domain: domain, severity: :suspend).exists?
|
||||
class << self
|
||||
def suspend?(domain)
|
||||
!!rule_for(domain)&.suspend?
|
||||
end
|
||||
|
||||
def silence?(domain)
|
||||
!!rule_for(domain)&.silence?
|
||||
end
|
||||
|
||||
def reject_media?(domain)
|
||||
!!rule_for(domain)&.reject_media?
|
||||
end
|
||||
|
||||
def reject_reports?(domain)
|
||||
!!rule_for(domain)&.reject_reports?
|
||||
end
|
||||
|
||||
alias blocked? suspend?
|
||||
|
||||
def rule_for(domain)
|
||||
return if domain.blank?
|
||||
|
||||
uri = Addressable::URI.new.tap { |u| u.host = domain.gsub(/[\/]/, '') }
|
||||
segments = uri.normalized_host.split('.')
|
||||
variants = segments.map.with_index { |_, i| segments[i..-1].join('.') }
|
||||
|
||||
where(domain: variants[0..-2]).order(Arel.sql('char_length(domain) desc')).first
|
||||
end
|
||||
end
|
||||
|
||||
def stricter_than?(other_block)
|
||||
return true if suspend?
|
||||
return true if suspend?
|
||||
return false if other_block.suspend? && (silence? || noop?)
|
||||
return false if other_block.silence? && noop?
|
||||
|
||||
(reject_media || !other_block.reject_media) && (reject_reports || !other_block.reject_reports)
|
||||
end
|
||||
|
||||
def affected_accounts_count
|
||||
scope = suspend? ? accounts.where(suspended_at: created_at) : accounts.where(silenced_at: created_at)
|
||||
scope.count
|
||||
end
|
||||
end
|
||||
|
@ -3,6 +3,7 @@
|
||||
class Form::AccountBatch
|
||||
include ActiveModel::Model
|
||||
include Authorization
|
||||
include Payloadable
|
||||
|
||||
attr_accessor :account_ids, :action, :current_account
|
||||
|
||||
@ -54,13 +55,7 @@ class Form::AccountBatch
|
||||
|
||||
return unless follow.account.activitypub?
|
||||
|
||||
json = ActiveModelSerializers::SerializableResource.new(
|
||||
follow,
|
||||
serializer: ActivityPub::RejectFollowSerializer,
|
||||
adapter: ActivityPub::Adapter
|
||||
).to_json
|
||||
|
||||
ActivityPub::DeliveryWorker.perform_async(json, current_account.id, follow.account.inbox_url)
|
||||
ActivityPub::DeliveryWorker.perform_async(Oj.dump(serialize_payload(follow, ActivityPub::RejectFollowSerializer)), current_account.id, follow.account.inbox_url)
|
||||
end
|
||||
|
||||
def approve!
|
||||
|
@ -35,6 +35,7 @@ class Form::StatusBatch
|
||||
def delete_statuses
|
||||
Status.where(id: status_ids).reorder(nil).find_each do |status|
|
||||
RemovalWorker.perform_async(status.id)
|
||||
Tombstone.find_or_create_by(uri: status.uri, account: status.account, by_moderator: true)
|
||||
log_action :destroy, status
|
||||
end
|
||||
|
||||
|
@ -8,15 +8,11 @@ class Instance
|
||||
def initialize(resource)
|
||||
@domain = resource.domain
|
||||
@accounts_count = resource.is_a?(DomainBlock) ? nil : resource.accounts_count
|
||||
@domain_block = resource.is_a?(DomainBlock) ? resource : DomainBlock.find_by(domain: domain)
|
||||
@domain_block = resource.is_a?(DomainBlock) ? resource : DomainBlock.rule_for(domain)
|
||||
end
|
||||
|
||||
def cached_sample_accounts
|
||||
Rails.cache.fetch("#{cache_key}/sample_accounts", expires_in: 12.hours) { Account.where(domain: domain).searchable.joins(:account_stat).popular.limit(3) }
|
||||
end
|
||||
|
||||
def cached_accounts_count
|
||||
@accounts_count || Rails.cache.fetch("#{cache_key}/count", expires_in: 12.hours) { Account.where(domain: domain).count }
|
||||
def countable?
|
||||
@accounts_count.present?
|
||||
end
|
||||
|
||||
def to_param
|
||||
|
@ -24,14 +24,16 @@
|
||||
class MediaAttachment < ApplicationRecord
|
||||
self.inheritance_column = nil
|
||||
|
||||
enum type: [:image, :gifv, :video, :unknown]
|
||||
enum type: [:image, :gifv, :video, :unknown, :audio]
|
||||
|
||||
IMAGE_FILE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.webp'].freeze
|
||||
VIDEO_FILE_EXTENSIONS = ['.webm', '.mp4', '.m4v', '.mov'].freeze
|
||||
AUDIO_FILE_EXTENSIONS = ['.ogg', '.oga', '.mp3', '.wav', '.flac', '.opus'].freeze
|
||||
|
||||
IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze
|
||||
VIDEO_MIME_TYPES = ['video/webm', 'video/mp4', 'video/quicktime'].freeze
|
||||
VIDEO_MIME_TYPES = ['video/webm', 'video/mp4', 'video/quicktime', 'video/ogg'].freeze
|
||||
VIDEO_CONVERTIBLE_MIME_TYPES = ['video/webm', 'video/quicktime'].freeze
|
||||
AUDIO_MIME_TYPES = ['audio/wave', 'audio/wav', 'audio/x-wav', 'audio/x-pn-wave', 'audio/ogg', 'audio/mpeg', 'audio/mp3', 'audio/webm', 'audio/flac'].freeze
|
||||
|
||||
BLURHASH_OPTIONS = {
|
||||
x_comp: 4,
|
||||
@ -65,8 +67,21 @@ class MediaAttachment < ApplicationRecord
|
||||
},
|
||||
}.freeze
|
||||
|
||||
AUDIO_STYLES = {
|
||||
original: {
|
||||
format: 'mp3',
|
||||
content_type: 'audio/mpeg',
|
||||
convert_options: {
|
||||
output: {
|
||||
'q:a' => 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
}.freeze
|
||||
|
||||
VIDEO_FORMAT = {
|
||||
format: 'mp4',
|
||||
content_type: 'video/mp4',
|
||||
convert_options: {
|
||||
output: {
|
||||
'loglevel' => 'fatal',
|
||||
@ -83,6 +98,11 @@ class MediaAttachment < ApplicationRecord
|
||||
},
|
||||
}.freeze
|
||||
|
||||
VIDEO_CONVERTED_STYLES = {
|
||||
small: VIDEO_STYLES[:small],
|
||||
original: VIDEO_FORMAT,
|
||||
}.freeze
|
||||
|
||||
IMAGE_LIMIT = 8.megabytes
|
||||
VIDEO_LIMIT = 40.megabytes
|
||||
|
||||
@ -95,9 +115,9 @@ class MediaAttachment < ApplicationRecord
|
||||
processors: ->(f) { file_processors f },
|
||||
convert_options: { all: '-quality 90 -strip' }
|
||||
|
||||
validates_attachment_content_type :file, content_type: IMAGE_MIME_TYPES + VIDEO_MIME_TYPES
|
||||
validates_attachment_size :file, less_than: IMAGE_LIMIT, unless: :video_or_gifv?
|
||||
validates_attachment_size :file, less_than: VIDEO_LIMIT, if: :video_or_gifv?
|
||||
validates_attachment_content_type :file, content_type: IMAGE_MIME_TYPES + VIDEO_MIME_TYPES + AUDIO_MIME_TYPES
|
||||
validates_attachment_size :file, less_than: IMAGE_LIMIT, unless: :larger_media_format?
|
||||
validates_attachment_size :file, less_than: VIDEO_LIMIT, if: :larger_media_format?
|
||||
remotable_attachment :file, VIDEO_LIMIT
|
||||
|
||||
include Attachmentable
|
||||
@ -120,8 +140,12 @@ class MediaAttachment < ApplicationRecord
|
||||
file.blank? && remote_url.present?
|
||||
end
|
||||
|
||||
def video_or_gifv?
|
||||
video? || gifv?
|
||||
def larger_media_format?
|
||||
video? || gifv? || audio?
|
||||
end
|
||||
|
||||
def audio_or_video?
|
||||
audio? || video?
|
||||
end
|
||||
|
||||
def to_param
|
||||
@ -153,33 +177,37 @@ class MediaAttachment < ApplicationRecord
|
||||
before_save :set_meta
|
||||
|
||||
class << self
|
||||
def supported_mime_types
|
||||
IMAGE_MIME_TYPES + VIDEO_MIME_TYPES + AUDIO_MIME_TYPES
|
||||
end
|
||||
|
||||
def supported_file_extensions
|
||||
IMAGE_FILE_EXTENSIONS + VIDEO_FILE_EXTENSIONS + AUDIO_FILE_EXTENSIONS
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def file_styles(f)
|
||||
if f.instance.file_content_type == 'image/gif'
|
||||
{
|
||||
small: IMAGE_STYLES[:small],
|
||||
original: VIDEO_FORMAT,
|
||||
}
|
||||
elsif IMAGE_MIME_TYPES.include? f.instance.file_content_type
|
||||
if f.instance.file_content_type == 'image/gif' || VIDEO_CONVERTIBLE_MIME_TYPES.include?(f.instance.file_content_type)
|
||||
VIDEO_CONVERTED_STYLES
|
||||
elsif IMAGE_MIME_TYPES.include?(f.instance.file_content_type)
|
||||
IMAGE_STYLES
|
||||
elsif VIDEO_CONVERTIBLE_MIME_TYPES.include?(f.instance.file_content_type)
|
||||
{
|
||||
small: VIDEO_STYLES[:small],
|
||||
original: VIDEO_FORMAT,
|
||||
}
|
||||
else
|
||||
elsif VIDEO_MIME_TYPES.include?(f.instance.file_content_type)
|
||||
VIDEO_STYLES
|
||||
else
|
||||
AUDIO_STYLES
|
||||
end
|
||||
end
|
||||
|
||||
def file_processors(f)
|
||||
if f.file_content_type == 'image/gif'
|
||||
[:gif_transcoder, :blurhash_transcoder]
|
||||
elsif VIDEO_MIME_TYPES.include? f.file_content_type
|
||||
[:video_transcoder, :blurhash_transcoder]
|
||||
elsif VIDEO_MIME_TYPES.include?(f.file_content_type)
|
||||
[:video_transcoder, :blurhash_transcoder, :type_corrector]
|
||||
elsif AUDIO_MIME_TYPES.include?(f.file_content_type)
|
||||
[:transcoder, :type_corrector]
|
||||
else
|
||||
[:lazy_thumbnail, :blurhash_transcoder]
|
||||
[:lazy_thumbnail, :blurhash_transcoder, :type_corrector]
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -202,7 +230,15 @@ class MediaAttachment < ApplicationRecord
|
||||
end
|
||||
|
||||
def set_type_and_extension
|
||||
self.type = VIDEO_MIME_TYPES.include?(file_content_type) ? :video : :image
|
||||
self.type = begin
|
||||
if VIDEO_MIME_TYPES.include?(file_content_type)
|
||||
:video
|
||||
elsif AUDIO_MIME_TYPES.include?(file_content_type)
|
||||
:audio
|
||||
else
|
||||
:image
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def set_meta
|
||||
@ -245,7 +281,7 @@ class MediaAttachment < ApplicationRecord
|
||||
frame_rate: movie.frame_rate,
|
||||
duration: movie.duration,
|
||||
bitrate: movie.bitrate,
|
||||
}
|
||||
}.compact
|
||||
end
|
||||
|
||||
def reset_parent_cache
|
||||
|
@ -41,9 +41,13 @@ class Notification < ApplicationRecord
|
||||
validates :account_id, uniqueness: { scope: [:activity_type, :activity_id] }
|
||||
validates :activity_type, inclusion: { in: TYPE_CLASS_MAP.values }
|
||||
|
||||
scope :browserable, ->(exclude_types = []) {
|
||||
scope :browserable, ->(exclude_types = [], account_id = nil) {
|
||||
types = TYPE_CLASS_MAP.values - activity_types_from_types(exclude_types + [:follow_request])
|
||||
where(activity_type: types)
|
||||
if account_id.nil?
|
||||
where(activity_type: types)
|
||||
else
|
||||
where(activity_type: types, from_account_id: account_id)
|
||||
end
|
||||
}
|
||||
|
||||
cache_associated :from_account, status: STATUS_INCLUDES, mention: [status: STATUS_INCLUDES], favourite: [:account, status: STATUS_INCLUDES], follow: :account, poll: [status: STATUS_INCLUDES]
|
||||
|
@ -17,6 +17,8 @@
|
||||
#
|
||||
|
||||
class Report < ApplicationRecord
|
||||
include Paginable
|
||||
|
||||
belongs_to :account
|
||||
belongs_to :target_account, class_name: 'Account'
|
||||
belongs_to :action_taken_by_account, class_name: 'Account', optional: true
|
||||
@ -26,6 +28,7 @@ class Report < ApplicationRecord
|
||||
|
||||
scope :unresolved, -> { where(action_taken: false) }
|
||||
scope :resolved, -> { where(action_taken: true) }
|
||||
scope :with_accounts, -> { includes([:account, :target_account, :action_taken_by_account, :assigned_account].each_with_object({}) { |k, h| h[k] = { user: [:invite_request, :invite] } }) }
|
||||
|
||||
validates :comment, length: { maximum: 1000 }
|
||||
|
||||
|
@ -9,9 +9,11 @@ class ReportFilter
|
||||
|
||||
def results
|
||||
scope = Report.unresolved
|
||||
|
||||
params.each do |key, value|
|
||||
scope = scope.merge scope_for(key, value)
|
||||
end
|
||||
|
||||
scope
|
||||
end
|
||||
|
||||
|
@ -86,8 +86,8 @@ class Status < ApplicationRecord
|
||||
scope :without_local_only, -> { where(local_only: [false, nil]) }
|
||||
scope :with_public_visibility, -> { where(visibility: :public) }
|
||||
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 :including_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced: true }) }
|
||||
scope :excluding_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced_at: nil }) }
|
||||
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_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) {
|
||||
@ -210,6 +210,8 @@ class Status < ApplicationRecord
|
||||
public_visibility? || unlisted_visibility?
|
||||
end
|
||||
|
||||
alias sign? distributable?
|
||||
|
||||
def with_media?
|
||||
media_attachments.any?
|
||||
end
|
||||
@ -509,7 +511,7 @@ class Status < ApplicationRecord
|
||||
return if direct_visibility?
|
||||
|
||||
account&.increment_count!(:statuses_count)
|
||||
reblog&.increment_count!(:reblogs_count) if reblog? && (public_visibility? || unlisted_visibility?)
|
||||
reblog&.increment_count!(:reblogs_count) if reblog?
|
||||
thread&.increment_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?)
|
||||
end
|
||||
|
||||
@ -517,7 +519,7 @@ class Status < ApplicationRecord
|
||||
return if direct_visibility? || marked_for_mass_destruction?
|
||||
|
||||
account&.decrement_count!(:statuses_count)
|
||||
reblog&.decrement_count!(:reblogs_count) if reblog? && (public_visibility? || unlisted_visibility?)
|
||||
reblog&.decrement_count!(:reblogs_count) if reblog?
|
||||
thread&.decrement_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?)
|
||||
end
|
||||
|
||||
|
@ -4,11 +4,12 @@
|
||||
#
|
||||
# Table name: tombstones
|
||||
#
|
||||
# id :bigint(8) not null, primary key
|
||||
# account_id :bigint(8)
|
||||
# uri :string not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# id :bigint(8) not null, primary key
|
||||
# account_id :bigint(8)
|
||||
# uri :string not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# by_moderator :boolean
|
||||
#
|
||||
|
||||
class Tombstone < ApplicationRecord
|
||||
|
@ -87,8 +87,9 @@ class User < ApplicationRecord
|
||||
scope :approved, -> { where(approved: true) }
|
||||
scope :confirmed, -> { where.not(confirmed_at: nil) }
|
||||
scope :enabled, -> { where(disabled: false) }
|
||||
scope :disabled, -> { where(disabled: true) }
|
||||
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(accounts: { suspended_at: nil }) }
|
||||
scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) }
|
||||
scope :emailable, -> { confirmed.enabled.joins(:account).merge(Account.searchable) }
|
||||
|
||||
@ -104,7 +105,8 @@ class User < ApplicationRecord
|
||||
|
||||
delegate :auto_play_gif, :default_sensitive, :unfollow_modal, :boost_modal, :delete_modal,
|
||||
:reduce_motion, :system_font_ui, :noindex, :theme, :display_media, :hide_network,
|
||||
:expand_spoilers, :default_language, :aggregate_reblogs, :show_application, :default_federation, to: :settings, prefix: :setting, allow_nil: false
|
||||
:expand_spoilers, :default_language, :aggregate_reblogs, :show_application,
|
||||
:advanced_layout, :default_federation, to: :settings, prefix: :setting, allow_nil: false
|
||||
|
||||
attr_reader :invite_code
|
||||
attr_writer :external
|
||||
|
Reference in New Issue
Block a user