about summary refs log tree commit diff
diff options
context:
space:
mode:
authormultiple creatures <dev@multiple-creature.party>2019-08-15 22:40:20 -0500
committermultiple creatures <dev@multiple-creature.party>2019-08-15 22:40:20 -0500
commit7bbcf793bc75b44f2b20de77b7774759af60cd90 (patch)
treed8d441c2d8cf245b28651efa14f6460841a8e304
parentf783ec279d03b7b56c96af5e18e0dd8c7a0710a1 (diff)
custom filters now have an option to add or override content warnings; filter caching has been fixed
-rw-r--r--app/controllers/api/v1/filters_controller.rb2
-rw-r--r--app/controllers/api/v1/statuses_controller.rb3
-rw-r--r--app/controllers/filters_controller.rb2
-rw-r--r--app/controllers/statuses_controller.rb4
-rw-r--r--app/helpers/filter_helper.rb24
-rw-r--r--app/models/custom_filter.rb12
-rw-r--r--app/serializers/rest/status_serializer.rb6
-rw-r--r--app/views/filters/_fields.html.haml4
-rw-r--r--config/locales/simple_form.en.yml2
-rw-r--r--db/migrate/20190815232125_add_custom_cws_to_custom_filters.rb8
-rw-r--r--db/schema.rb4
11 files changed, 64 insertions, 7 deletions
diff --git a/app/controllers/api/v1/filters_controller.rb b/app/controllers/api/v1/filters_controller.rb
index 48177f41a..760218d62 100644
--- a/app/controllers/api/v1/filters_controller.rb
+++ b/app/controllers/api/v1/filters_controller.rb
@@ -43,6 +43,6 @@ class Api::V1::FiltersController < Api::BaseController
   end
 
   def resource_params
-    params.permit(:phrase, :expires_in, :irreversible, :whole_word, :exclude_media, :media_only, :status_text, :spoiler, :tags, context: [])
+    params.permit(:phrase, :expires_in, :irreversible, :whole_word, :exclude_media, :media_only, :status_text, :spoiler, :tags, :custom_cw, :override_cw, context: [])
   end
 end
diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb
index fa3483822..a5ea12591 100644
--- a/app/controllers/api/v1/statuses_controller.rb
+++ b/app/controllers/api/v1/statuses_controller.rb
@@ -2,6 +2,7 @@
 
 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]
@@ -18,6 +19,8 @@ class Api::V1::StatusesController < Api::BaseController
 
   def show
     @status = cache_collection([@status], Status).first
+    # make sure any custom cws are applied
+    phrase_filtered?(@status, current_account.id, 'thread') unless current_account.nil?
     render json: @status, serializer: REST::StatusSerializer
   end
 
diff --git a/app/controllers/filters_controller.rb b/app/controllers/filters_controller.rb
index 55ee05833..c58da753b 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, :spoiler, :tags, :thread, :media_only, context: [])
+    params.require(:custom_filter).permit(:phrase, :expires_in, :irreversible, :whole_word, :exclude_media, :media_only, :status_text, :spoiler, :tags, :custom_cw, :override_cw, context: [])
   end
 
   def set_body_classes
diff --git a/app/controllers/statuses_controller.rb b/app/controllers/statuses_controller.rb
index 6fd937f8d..7af237da4 100644
--- a/app/controllers/statuses_controller.rb
+++ b/app/controllers/statuses_controller.rb
@@ -3,6 +3,7 @@
 class StatusesController < ApplicationController
   include SignatureAuthentication
   include Authorization
+  include FilterHelper
 
   ANCESTORS_LIMIT         = 40
   DESCENDANTS_LIMIT       = 60
@@ -192,6 +193,9 @@ class StatusesController < ApplicationController
     @type         = @stream_entry.activity_type.downcase
     @sharekey     = params[:key]
 
+    # make sure any custom cws are applied
+    phrase_filtered?(@status, current_account.id, 'thread') unless current_account.nil?
+
     if @status.sharekey.present? && @sharekey == @status.sharekey
       skip_authorization
     else
diff --git a/app/helpers/filter_helper.rb b/app/helpers/filter_helper.rb
index 3de27168d..ca5b32d1a 100644
--- a/app/helpers/filter_helper.rb
+++ b/app/helpers/filter_helper.rb
@@ -1,7 +1,10 @@
 module FilterHelper
+  include Redisable
+
 	def phrase_filtered?(status, receiver_id, context)
-    filters = Rails.cache.fetch("filters:#{receiver_id}") { CustomFilter.where(account_id: receiver_id).active_irreversible.to_a }.to_a
+    return true if redis.sismember("filtered_statuses:#{receiver_id}", status.id)
 
+    filters = cached_filters(receiver_id)
     filters.select! { |filter| filter.context.include?(context.to_s) && !filter.expired? }
 
     if status.media_attachments.any?
@@ -34,6 +37,17 @@ module FilterHelper
 
       if matched
         filter_thread(receiver_id, status.conversation_id) if filter.thread
+
+        unless filter.custom_cw.nil?
+          cw = if filter.override_cw || status.spoiler_text.blank?
+                 filter.custom_cw
+               else
+                 "[#{filter.custom_cw}] #{status.spoiler_text}".rstrip
+               end
+          redis.hset("custom_cw:#{receiver_id}", status.id, cw)
+        end
+
+        redis.sadd("filtered_statuses:#{receiver_id}", status.id)
         return true
       end
     end
@@ -43,10 +57,14 @@ module FilterHelper
 
   def filter_thread(account_id, conversation_id)
     return if Status.where(account_id: account_id, conversation_id: conversation_id).exists?
-    Redis.current.sadd("filtered_threads:#{account_id}", conversation_id)
+    redis.sadd("filtered_threads:#{account_id}", conversation_id)
   end
 
   def filtering_thread?(account_id, conversation_id)
-    Redis.current.sismember("filtered_threads:#{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/models/custom_filter.rb b/app/models/custom_filter.rb
index a1db3940c..ddf6cc7ab 100644
--- a/app/models/custom_filter.rb
+++ b/app/models/custom_filter.rb
@@ -18,6 +18,8 @@
 #  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
 #
 
 class CustomFilter < ApplicationRecord
@@ -29,6 +31,7 @@ class CustomFilter < ApplicationRecord
   ).freeze
 
   include Expireable
+  include Redisable
 
   belongs_to :account
 
@@ -38,6 +41,7 @@ class CustomFilter < ApplicationRecord
 
   scope :active_irreversible, -> { where(irreversible: true).where(Arel.sql('expires_at IS NULL OR expires_at > NOW()')) }
 
+  before_validation :prepare_custom_cw
   before_validation :clean_up_contexts
   after_commit :remove_cache
 
@@ -47,9 +51,15 @@ class CustomFilter < ApplicationRecord
     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}")
-    Rails.cache.delete("filtered_threads:#{account_id}")
+    redis.del("custom_cw:#{account_id}")
+    redis.del("filtered_threads:#{account_id}")
+    redis.del("filtered_statuses:#{account_id}")
     Redis.current.publish("timeline:#{account_id}", Oj.dump(event: :filters_changed))
   end
 
diff --git a/app/serializers/rest/status_serializer.rb b/app/serializers/rest/status_serializer.rb
index 7146d8108..d41d1ba43 100644
--- a/app/serializers/rest/status_serializer.rb
+++ b/app/serializers/rest/status_serializer.rb
@@ -1,6 +1,8 @@
 # frozen_string_literal: true
 
 class REST::StatusSerializer < ActiveModel::Serializer
+  include Redisable
+
   attributes :id, :created_at, :in_reply_to_id, :in_reply_to_account_id,
              :sensitive, :spoiler_text, :visibility, :language,
              :uri, :url, :replies_count, :reblogs_count,
@@ -55,6 +57,10 @@ class REST::StatusSerializer < ActiveModel::Serializer
     object.account.user_shows_application? || owner?
   end
 
+  def spoiler_text
+    redis.hget("custom_cw:#{current_user&.account_id}", object.id) || object.spoiler_text
+  end
+
   def visibility
     if object.limited_visibility?
       'private'
diff --git a/app/views/filters/_fields.html.haml b/app/views/filters/_fields.html.haml
index 8229cb728..33c2ada31 100644
--- a/app/views/filters/_fields.html.haml
+++ b/app/views/filters/_fields.html.haml
@@ -22,3 +22,7 @@
   = f.input :thread, wrapper: :with_label
   = 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/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
index 809c5dee8..953c97d75 100644
--- a/config/locales/simple_form.en.yml
+++ b/config/locales/simple_form.en.yml
@@ -181,6 +181,8 @@ en:
         username: Username
         username_or_email: Username or Email
         whole_word: Whole word
+        custom_cw: Set or prepend content warning
+        override_cw: Override existing content warning
       boost_interval:
         1: 1 minute
         2: 2 minutes
diff --git a/db/migrate/20190815232125_add_custom_cws_to_custom_filters.rb b/db/migrate/20190815232125_add_custom_cws_to_custom_filters.rb
new file mode 100644
index 000000000..ec201e7b6
--- /dev/null
+++ b/db/migrate/20190815232125_add_custom_cws_to_custom_filters.rb
@@ -0,0 +1,8 @@
+class AddCustomCwsToCustomFilters < ActiveRecord::Migration[5.2]
+  def change
+    safety_assured {
+      add_column :custom_filters, :custom_cw, :text
+      add_column :custom_filters, :override_cw, :boolean, null: false, default: false
+    }
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 7f7d31bd2..16b284b58 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_08_07_221924) do
+ActiveRecord::Schema.define(version: 2019_08_15_232125) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -256,6 +256,8 @@ ActiveRecord::Schema.define(version: 2019_08_07_221924) do
     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.index ["account_id"], name: "index_custom_filters_on_account_id"
   end