forked from asonix/mastodon
Fixes #12795 It was already possible to create domain blocks for TLDs, but those weren't enforced, nor editable. This commit changes it so that they are enforced and editable.
73 lines
2.3 KiB
Ruby
73 lines
2.3 KiB
Ruby
# frozen_string_literal: true
|
|
# == Schema Information
|
|
#
|
|
# Table name: domain_blocks
|
|
#
|
|
# id :bigint(8) not null, primary key
|
|
# domain :string default(""), not null
|
|
# created_at :datetime not null
|
|
# updated_at :datetime not null
|
|
# severity :integer default("silence")
|
|
# reject_media :boolean default(FALSE), not null
|
|
# reject_reports :boolean default(FALSE), not null
|
|
# private_comment :text
|
|
# public_comment :text
|
|
#
|
|
|
|
class DomainBlock < ApplicationRecord
|
|
include DomainNormalizable
|
|
|
|
enum severity: [:silence, :suspend, :noop]
|
|
|
|
validates :domain, presence: true, uniqueness: true, domain: true
|
|
|
|
has_many :accounts, foreign_key: :domain, primary_key: :domain
|
|
delegate :count, to: :accounts, prefix: true
|
|
|
|
scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) }
|
|
scope :with_user_facing_limitations, -> { where(severity: [:silence, :suspend]).or(where(reject_media: true)) }
|
|
scope :by_severity, -> { order(Arel.sql('(CASE severity WHEN 0 THEN 1 WHEN 1 THEN 2 WHEN 2 THEN 0 END), reject_media, domain')) }
|
|
|
|
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).order(Arel.sql('char_length(domain) desc')).first
|
|
end
|
|
end
|
|
|
|
def stricter_than?(other_block)
|
|
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
|