diff --git a/app/models/status.rb b/app/models/status.rb index ed4bcefca6a..37f2db56248 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -59,6 +59,7 @@ class Status < ApplicationRecord validates :uri, uniqueness: true, presence: true, unless: :local? validates :text, presence: true, unless: -> { with_media? || reblog? } validates_with StatusLengthValidator + validates_with DisallowedHashtagsValidator validates :reblog, uniqueness: { scope: :account }, if: :reblog? default_scope { recent } diff --git a/app/validators/disallowed_hashtags_validator.rb b/app/validators/disallowed_hashtags_validator.rb new file mode 100644 index 00000000000..22c027b0fca --- /dev/null +++ b/app/validators/disallowed_hashtags_validator.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class DisallowedHashtagsValidator < ActiveModel::Validator + def validate(status) + return unless status.local? && !status.reblog? + + tags = Extractor.extract_hashtags(status.text) + tags.keep_if { |tag| disallowed_hashtags.include? tag.downcase } + + status.errors.add(:text, I18n.t('statuses.disallowed_hashtags', tags: tags.join(', '), count: tags.size)) unless tags.empty? + end + + private + + def disallowed_hashtags + return @disallowed_hashtags if @disallowed_hashtags + + @disallowed_hashtags = Setting.disallowed_hashtags.nil? ? [] : Setting.disallowed_hashtags + @disallowed_hashtags = @disallowed_hashtags.split(' ') if @disallowed_hashtags.is_a? String + @disallowed_hashtags = @disallowed_hashtags.map(&:downcase) + end +end diff --git a/config/locales/en.yml b/config/locales/en.yml index 8b66b91ec4b..1468d85598e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -684,6 +684,9 @@ en: one: "%{count} video" other: "%{count} videos" content_warning: 'Content warning: %{warning}' + disallowed_hashtags: + one: 'contained a disallowed hashtag: %{tags}' + other: 'contained the disallowed hashtags: %{tags}' open_in_web: Open in web over_character_limit: character limit of %{max} exceeded pin_errors: diff --git a/config/settings.yml b/config/settings.yml index 68579ad0f06..dcf655008fc 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -47,6 +47,7 @@ defaults: &defaults - root - webmaster - administrator + disallowed_hashtags: # space separated string or list of hashtags without the hash bootstrap_timeline_accounts: '' activity_api_enabled: true peers_api_enabled: true