about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/api/v1/filters_controller.rb4
-rw-r--r--app/controllers/api/v1/statuses_controller.rb1
-rw-r--r--app/controllers/filters_controller.rb2
-rw-r--r--app/helpers/filter_helper.rb78
-rw-r--r--app/lib/feed_manager.rb6
-rw-r--r--app/lib/status_filter.rb6
-rw-r--r--app/models/custom_filter.rb56
-rw-r--r--app/serializers/rest/filter_serializer.rb7
-rw-r--r--app/views/filters/_fields.html.haml23
-rw-r--r--db/migrate/20191118044943_remove_old_filter_columns.rb18
-rw-r--r--db/migrate/20191118064252_remove_context_from_custom_filters.rb5
-rw-r--r--db/schema.rb19
12 files changed, 49 insertions, 176 deletions
diff --git a/app/controllers/api/v1/filters_controller.rb b/app/controllers/api/v1/filters_controller.rb
index 8194480fa..de2c90dba 100644
--- a/app/controllers/api/v1/filters_controller.rb
+++ b/app/controllers/api/v1/filters_controller.rb
@@ -35,7 +35,7 @@ class Api::V1::FiltersController < Api::BaseController
   private
 
   def set_filters
-    @filters = params['all'].to_i == 1 ? current_account.custom_filters : current_account.custom_filters.where(custom_cw: nil)
+    @filters = params['all'].to_i == 1 ? current_account.custom_filters : []
   end
 
   def set_filter
@@ -43,6 +43,6 @@ class Api::V1::FiltersController < Api::BaseController
   end
 
   def resource_params
-    params.permit(:phrase, :expires_in, :whole_word, :exclude_media, :media_only, :status_text, :spoiler, :tags, :custom_cw, :override_cw, :desc, :no_desc, context: [])
+    params.permit(:phrase, :expires_in)
   end
 end
diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb
index 601e400ca..fa3483822 100644
--- a/app/controllers/api/v1/statuses_controller.rb
+++ b/app/controllers/api/v1/statuses_controller.rb
@@ -2,7 +2,6 @@
 
 class Api::V1::StatusesController < Api::BaseController
   include Authorization
-  include FilterHelper
 
   before_action -> { authorize_if_got_token! :read, :'read:statuses' }, except: [:create, :destroy]
   before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only:   [:create, :destroy]
diff --git a/app/controllers/filters_controller.rb b/app/controllers/filters_controller.rb
index 8a4636ba2..9fa653b11 100644
--- a/app/controllers/filters_controller.rb
+++ b/app/controllers/filters_controller.rb
@@ -58,7 +58,7 @@ class FiltersController < ApplicationController
   end
 
   def resource_params
-    params.require(:custom_filter).permit(:phrase, :expires_in, :irreversible, :whole_word, :exclude_media, :media_only, :status_text, :spoiler, :tags, :custom_cw, :override_cw, :desc, :no_desc, context: [])
+    params.require(:custom_filter).permit(:phrase, :expires_in)
   end
 
   def set_body_classes
diff --git a/app/helpers/filter_helper.rb b/app/helpers/filter_helper.rb
index 77ffa98be..b2f1b00fc 100644
--- a/app/helpers/filter_helper.rb
+++ b/app/helpers/filter_helper.rb
@@ -1,83 +1,17 @@
 module FilterHelper
   include Redisable
 
-	def phrase_filtered?(status, receiver_id, context)
-    if redis.sismember("filtered_statuses:#{receiver_id}", status.id)
-      return !(redis.hexists("custom_cw:#{receiver_id}", status.id) || redis.hexists("custom_cw:#{receiver_id}", "c#{status.conversation_id}"))
-    end
-
-    filters = cached_filters(receiver_id).select { |filter| !filter.expired? }
-
-    unless context.nil?
-      filters.select! { |filter| filter.context.include?(context.to_s) && !filter.expired? }
-    end
-
-    if status.media_attachments.any?
-      filters.delete_if { |filter| filter.exclude_media }
-    else
-      filters.delete_if { |filter| filter.media_only }
-    end
-
-    return false if filters.empty?
+	def phrase_filtered?(status, receiver_id)
+    return true if redis.sismember("filtered_statuses:#{receiver_id}", status.id)
+    return false unless CustomFilter.where(account_id: receiver_id).exists?
 
     status = status.reblog if status.reblog?
-    status_text = status.normalized_text
-    spoiler_text = status.spoiler_text
-    tags = status.tags.pluck(:name).join("\n")
-    descs = status.media_attachments.map { |a| a.description }.join("\n").strip
-
-    filters.each do |filter|
-      if filter.whole_word
-        sb = filter.phrase =~ /\A[[:word:]]/ ? '\b' : ''
-        eb = filter.phrase =~ /[[:word:]]\z/ ? '\b' : ''
-
-        regex = /(?mix:#{sb}#{Regexp.escape(filter.phrase)}#{eb})/
-      else
-        regex = /#{Regexp.escape(filter.phrase)}/i
-      end
-
-      matched = false
-      matched ||= regex.match(status_text).present? if filter.status_text
-      matched ||= regex.match(spoiler_text).present? if filter.spoiler && spoiler_text.present?
-      matched ||= regex.match(tags).present? if filter.tags && tags.present?
-      matched ||= regex.match(descs).present? if filter.desc && descs.present?
-      matched ||= status.media_attachments.all { |a| a.description.blank? } if filter.no_desc && status.media_attachments.any?
 
-      if matched
-        filter_thread(receiver_id, status.conversation_id) if filter.thread && filter.custom_cw.blank?
-
-        unless filter.custom_cw.blank?
-          cw = if filter.override_cw || status.spoiler_text.blank?
-                 filter.custom_cw
-               else
-                 "[#{filter.custom_cw}] #{status.spoiler_text}".rstrip
-               end
-
-          if filter.thread
-            redis.hset("custom_cw:#{receiver_id}", "c#{status.conversation_id}", cw)
-          else
-            redis.hset("custom_cw:#{receiver_id}", status.id, cw)
-          end
-        end
-
-        redis.sadd("filtered_statuses:#{receiver_id}", status.id)
-        return filter.custom_cw.blank?
-      end
+    if Status.where(id: status.id).where("statuses.normalized_text ~ ANY(ARRAY(SELECT unaccent(lower(phrase)) FROM custom_filters WHERE account_id = ?))", receiver_id).exists?
+      redis.sadd("filtered_statuses:#{receiver_id}", status.id)
+      return true
     end
 
     false
   end
-
-  def filter_thread(account_id, conversation_id)
-    return if Status.where(account_id: account_id, conversation_id: conversation_id).exists?
-    redis.sadd("filtered_threads:#{account_id}", conversation_id)
-  end
-
-  def filtering_thread?(account_id, conversation_id)
-    redis.sismember("filtered_threads:#{account_id}", conversation_id)
-  end
-
-  def cached_filters(account_id)
-    Rails.cache.fetch("filters:#{account_id}") { CustomFilter.where(account_id: account_id).to_a }.to_a
-  end
 end
diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb
index 6d8f46e6f..b2f040811 100644
--- a/app/lib/feed_manager.rb
+++ b/app/lib/feed_manager.rb
@@ -157,8 +157,7 @@ class FeedManager
   def filter_from_home?(status, receiver_id)
     return false if receiver_id == status.account_id
     return true  if status.reply? && (status.in_reply_to_id.nil? || status.in_reply_to_account_id.nil?)
-    return true  if filtering_thread?(receiver_id, status.conversation_id)
-    return true  if phrase_filtered?(status, receiver_id, :home)
+    return true  if phrase_filtered?(status, receiver_id)
 
     check_for_blocks = status.active_mentions.pluck(:account_id)
     check_for_blocks.concat([status.account_id])
@@ -188,8 +187,7 @@ class FeedManager
 
   def filter_from_mentions?(status, receiver_id)
     return true if receiver_id == status.account_id
-    return true if filtering_thread?(receiver_id, status.conversation_id)
-    return true if phrase_filtered?(status, receiver_id, :notifications)
+    return true if phrase_filtered?(status, receiver_id)
 
     # This filter is called from NotifyService, but already after the sender of
     # the notification has been checked for mute/block. Therefore, it's not
diff --git a/app/lib/status_filter.rb b/app/lib/status_filter.rb
index d70ed1d21..0cc1ce85c 100644
--- a/app/lib/status_filter.rb
+++ b/app/lib/status_filter.rb
@@ -23,7 +23,6 @@ class StatusFilter
   end
 
   def filtered_status?
-    return true if filtering_thread?(account.id, status.conversation_id)
     blocking_account? || blocking_domain? || muting_account? || filtered_reference?
   end
 
@@ -34,7 +33,7 @@ class StatusFilter
     return true if account.user_hides_replies_of_blocker? && reply_to_blocker?
 
     # filtered by user?
-    return true if phrase_filtered?(status, account.id, nil)
+    return true if phrase_filtered?(status, account.id)
 
     # kajiht has no filters if status has no mentions
     return false if status&.mentions.blank?
@@ -46,6 +45,9 @@ class StatusFilter
     # Don't filter statuses mentioning you.
     return false if mentioned_account_ids.include?(account.id)
 
+    # Filter posts missing media descriptions.
+    return true if account.filter_undescribed? && status.media_attachments.all? { |attachment| attachment.description.blank? }
+
     return true if account.user_hides_mentions_of_blocked? && mentioned_accounts.where.not(suspended_at: nil).exists?
 
     return true if mentioned_account_ids.any? do |mentioned_account_id|
diff --git a/app/models/custom_filter.rb b/app/models/custom_filter.rb
index 5feb5fd7d..28d413d9b 100644
--- a/app/models/custom_filter.rb
+++ b/app/models/custom_filter.rb
@@ -3,60 +3,26 @@
 #
 # Table name: custom_filters
 #
-#  id            :bigint(8)        not null, primary key
-#  account_id    :bigint(8)
-#  expires_at    :datetime
-#  phrase        :text             default(""), not null
-#  context       :string           default([]), not null, is an Array
-#  irreversible  :boolean          default(FALSE), not null
-#  created_at    :datetime         not null
-#  updated_at    :datetime         not null
-#  whole_word    :boolean          default(TRUE), not null
-#  exclude_media :boolean          default(FALSE), not null
-#  media_only    :boolean          default(FALSE), not null
-#  thread        :boolean          default(FALSE), not null
-#  spoiler       :boolean          default(FALSE), not null
-#  tags          :boolean          default(FALSE), not null
-#  status_text   :boolean          default(FALSE), not null
-#  custom_cw     :text
-#  override_cw   :boolean          default(FALSE), not null
-#  desc          :boolean          default(FALSE), not null
-#  no_desc       :boolean          default(FALSE), not null
+#  id         :bigint(8)        not null, primary key
+#  account_id :bigint(8)
+#  expires_at :datetime
+#  phrase     :text             default(""), not null
+#  created_at :datetime         not null
+#  updated_at :datetime         not null
 #
 
 class CustomFilter < ApplicationRecord
-  VALID_CONTEXTS = %w(
-    home
-    notifications
-    public
-    thread
-  ).freeze
-
   include Expireable
   include Redisable
 
   belongs_to :account
 
-  validates :phrase, :context, presence: true
-  validate :context_must_be_valid
-  validate :irreversible_must_be_within_context
-
-  scope :active_irreversible, -> { where(irreversible: true).where(Arel.sql('expires_at IS NULL OR expires_at > NOW()')) }
+  validates :phrase, presence: true
 
-  before_validation :prepare_custom_cw
-  before_validation :clean_up_contexts
   after_commit :remove_cache
 
   private
 
-  def clean_up_contexts
-    self.context = Array(context).map(&:strip).map(&:presence).compact
-  end
-
-  def prepare_custom_cw
-    custom_cw&.strip!
-  end
-
   def remove_cache
     Rails.cache.delete("filters:#{account_id}")
     redis.del("custom_cw:#{account_id}")
@@ -64,12 +30,4 @@ class CustomFilter < ApplicationRecord
     redis.del("filtered_statuses:#{account_id}")
     Redis.current.publish("timeline:#{account_id}", Oj.dump(event: :filters_changed))
   end
-
-  def context_must_be_valid
-    errors.add(:context, I18n.t('filters.errors.invalid_context')) if context.empty? || context.any? { |c| !VALID_CONTEXTS.include?(c) }
-  end
-
-  def irreversible_must_be_within_context
-    errors.add(:irreversible, I18n.t('filters.errors.invalid_irreversible')) if irreversible? && !context.include?('home') && !context.include?('notifications')
-  end
 end
diff --git a/app/serializers/rest/filter_serializer.rb b/app/serializers/rest/filter_serializer.rb
index b027e9cc1..6d72aa426 100644
--- a/app/serializers/rest/filter_serializer.rb
+++ b/app/serializers/rest/filter_serializer.rb
@@ -1,14 +1,9 @@
 # frozen_string_literal: true
 
 class REST::FilterSerializer < ActiveModel::Serializer
-  attributes :id, :phrase, :context, :whole_word, :expires_at,
-             :irreversible, :exclude_media, :media_only
+  attributes :id, :phrase, :expires_at
 
   def id
     object.id.to_s
   end
-
-  def irreversible
-    true
-  end
 end
diff --git a/app/views/filters/_fields.html.haml b/app/views/filters/_fields.html.haml
index da0add2ea..afa72ae0c 100644
--- a/app/views/filters/_fields.html.haml
+++ b/app/views/filters/_fields.html.haml
@@ -6,26 +6,3 @@
 
 .fields-group
   = f.input :context, wrapper: :with_block_label, collection: CustomFilter::VALID_CONTEXTS, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', label_method: lambda { |context| I18n.t("filters.contexts.#{context}") }, include_blank: false
-
-%hr.spacer/
-
-.fields-group
-  = f.input :whole_word, wrapper: :with_label
-
-.fields-group
-  = f.input :status_text, wrapper: :with_label
-  = f.input :spoiler, wrapper: :with_label
-  = f.input :tags, wrapper: :with_label
-  = f.input :thread, wrapper: :with_label
-
-.fields-group
-  = f.input :desc, wrapper: :with_label
-  = f.input :no_desc, wrapper: :with_label
-
-.fields-group
-  = f.input :media_only, wrapper: :with_label
-  = f.input :exclude_media, wrapper: :with_label
-
-.fields-group
-  = f.input :custom_cw, as: :string, wrapper: :with_label
-  = f.input :override_cw, wrapper: :with_label
diff --git a/db/migrate/20191118044943_remove_old_filter_columns.rb b/db/migrate/20191118044943_remove_old_filter_columns.rb
new file mode 100644
index 000000000..b5236e7a4
--- /dev/null
+++ b/db/migrate/20191118044943_remove_old_filter_columns.rb
@@ -0,0 +1,18 @@
+class RemoveOldFilterColumns < ActiveRecord::Migration[5.2]
+  def change
+    safety_assured {
+      remove_column :custom_filters, :no_desc
+      remove_column :custom_filters, :desc
+      remove_column :custom_filters, :custom_cw
+      remove_column :custom_filters, :override_cw
+      remove_column :custom_filters, :status_text
+      remove_column :custom_filters, :tags
+      remove_column :custom_filters, :spoiler
+      remove_column :custom_filters, :thread
+      remove_column :custom_filters, :media_only
+      remove_column :custom_filters, :exclude_media
+      remove_column :custom_filters, :whole_word
+      remove_column :custom_filters, :irreversible
+    }
+  end
+end
diff --git a/db/migrate/20191118064252_remove_context_from_custom_filters.rb b/db/migrate/20191118064252_remove_context_from_custom_filters.rb
new file mode 100644
index 000000000..3206e9491
--- /dev/null
+++ b/db/migrate/20191118064252_remove_context_from_custom_filters.rb
@@ -0,0 +1,5 @@
+class RemoveContextFromCustomFilters < ActiveRecord::Migration[5.2]
+  def change
+    safety_assured { remove_column :custom_filters, :context }
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 93b770e2d..0e5aca23d 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 2019_11_18_005833) do
+ActiveRecord::Schema.define(version: 2019_11_18_064252) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "pg_trgm"
@@ -251,21 +251,8 @@ ActiveRecord::Schema.define(version: 2019_11_18_005833) do
     t.bigint "account_id"
     t.datetime "expires_at"
     t.text "phrase", default: "", null: false
-    t.string "context", default: [], null: false, array: true
-    t.boolean "irreversible", default: false, null: false
-    t.datetime "created_at", null: false
-    t.datetime "updated_at", null: false
-    t.boolean "whole_word", default: true, null: false
-    t.boolean "exclude_media", default: false, null: false
-    t.boolean "media_only", default: false, null: false
-    t.boolean "thread", default: false, null: false
-    t.boolean "spoiler", default: false, null: false
-    t.boolean "tags", default: false, null: false
-    t.boolean "status_text", default: false, null: false
-    t.text "custom_cw"
-    t.boolean "override_cw", default: false, null: false
-    t.boolean "desc", default: false, null: false
-    t.boolean "no_desc", default: false, null: false
+    t.datetime "created_at", null: false
+    t.datetime "updated_at", null: false
     t.index ["account_id"], name: "index_custom_filters_on_account_id"
   end