about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
authormultiple creatures <dev@multiple-creature.party>2020-01-10 20:07:15 -0600
committermultiple creatures <dev@multiple-creature.party>2020-01-10 20:07:15 -0600
commit1268277a8c203bcae515e0ccc8b3432119bafed2 (patch)
tree89fccc698a4a148f70a3ae10faf0ffef260200ec /app
parent0090aca0453285ed6f4d55758ccd05200025d11a (diff)
add custom filter master toggle, add media gallery mode, & fix various filter logic + caching bugs
Diffstat (limited to 'app')
-rw-r--r--app/controllers/api/v1/filters_controller.rb7
-rw-r--r--app/controllers/api/v1/timelines/home_controller.rb9
-rw-r--r--app/controllers/api/v1/timelines/list_controller.rb10
-rw-r--r--app/controllers/filters_controller.rb7
-rw-r--r--app/controllers/settings/preferences_controller.rb18
-rw-r--r--app/helpers/filter_helper.rb8
-rw-r--r--app/lib/status_filter.rb17
-rw-r--r--app/models/account.rb1
-rw-r--r--app/models/status.rb10
-rw-r--r--app/models/user.rb3
-rw-r--r--app/views/settings/preferences/show.html.haml60
-rw-r--r--app/views/settings/profiles/show.html.haml5
12 files changed, 101 insertions, 54 deletions
diff --git a/app/controllers/api/v1/filters_controller.rb b/app/controllers/api/v1/filters_controller.rb
index 514f7c8fa..ffef0b920 100644
--- a/app/controllers/api/v1/filters_controller.rb
+++ b/app/controllers/api/v1/filters_controller.rb
@@ -15,6 +15,7 @@ class Api::V1::FiltersController < Api::BaseController
 
   def create
     @filter = current_account.custom_filters.create!(resource_params)
+    toggle_filters
     render json: @filter, serializer: REST::FilterSerializer
   end
 
@@ -24,16 +25,22 @@ class Api::V1::FiltersController < Api::BaseController
 
   def update
     @filter.update!(resource_params)
+    toggle_filters
     render json: @filter, serializer: REST::FilterSerializer
   end
 
   def destroy
     @filter.destroy!
+    toggle_filters
     render_empty
   end
 
   private
 
+  def toggle_filters
+    current_account.user.update!(filters_enabled: !current_account.custom_filters.enabled.blank?)
+  end
+
   def set_filters
     @filters = params['all'].to_i == 1 ? current_account.custom_filters : []
   end
diff --git a/app/controllers/api/v1/timelines/home_controller.rb b/app/controllers/api/v1/timelines/home_controller.rb
index bd3bac0fe..589bc3486 100644
--- a/app/controllers/api/v1/timelines/home_controller.rb
+++ b/app/controllers/api/v1/timelines/home_controller.rb
@@ -23,11 +23,10 @@ class Api::V1::Timelines::HomeController < Api::BaseController
   end
 
   def cached_home_statuses
-    if current_account&.user&.hide_boosts
-      cache_collection home_statuses.without_reblogs, Status
-    else
-      cache_collection home_statuses, Status
-    end
+    statuses = home_statuses
+    statuses = statuses.without_reblogs if current_account&.user&.hide_boosts
+    statuses = statuses.with_media if current_account&.user&.media_only
+    cache_collection statuses, Status
   end
 
   def home_statuses
diff --git a/app/controllers/api/v1/timelines/list_controller.rb b/app/controllers/api/v1/timelines/list_controller.rb
index 7eb656745..b52f53bf9 100644
--- a/app/controllers/api/v1/timelines/list_controller.rb
+++ b/app/controllers/api/v1/timelines/list_controller.rb
@@ -25,11 +25,11 @@ class Api::V1::Timelines::ListController < Api::BaseController
   end
 
   def cached_list_statuses
-    if current_account&.user&.hide_boosts
-      cache_collection list_statuses.without_reblogs, Status
-    else
-      cache_collection list_statuses, Status
-    end
+    statuses = list_statuses
+    statuses = statuses.without_reblogs if current_account&.user&.hide_boosts
+    statuses = statuses.with_media if current_account&.user&.media_only
+
+    cache_collection statuses, Status
   end
 
   def list_statuses
diff --git a/app/controllers/filters_controller.rb b/app/controllers/filters_controller.rb
index f5cc00d2f..2b615923f 100644
--- a/app/controllers/filters_controller.rb
+++ b/app/controllers/filters_controller.rb
@@ -22,6 +22,7 @@ class FiltersController < ApplicationController
     @filter = current_account.custom_filters.build(resource_params)
 
     if @filter.save
+      toggle_filters
       redirect_to filters_path
     else
       render action: :new
@@ -32,6 +33,7 @@ class FiltersController < ApplicationController
 
   def update
     if @filter.update(resource_params)
+      toggle_filters
       redirect_to filters_path
     else
       render action: :edit
@@ -40,11 +42,16 @@ class FiltersController < ApplicationController
 
   def destroy
     @filter.destroy
+    toggle_filters
     redirect_to filters_path
   end
 
   private
 
+  def toggle_filters
+    current_user.update!(filters_enabled: !current_account.custom_filters.enabled.blank?)
+  end
+
   def set_pack
     use_pack 'settings'
   end
diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb
index 2ff84ac80..ce3c84f77 100644
--- a/app/controllers/settings/preferences_controller.rb
+++ b/app/controllers/settings/preferences_controller.rb
@@ -14,6 +14,9 @@ class Settings::PreferencesController < Settings::BaseController
 
     if current_user.update(user_params)
       I18n.locale = current_user.locale
+      toggle_filters
+      remove_cache
+      update_feeds
       redirect_to settings_preferences_path, notice: I18n.t('generic.changes_saved_msg')
     else
       render :show
@@ -22,6 +25,18 @@ class Settings::PreferencesController < Settings::BaseController
 
   private
 
+  def toggle_filters
+    current_user.update!(filters_enabled: !current_account.custom_filters.enabled.blank?)
+  end
+
+  def update_feeds
+    FilterFeedsWorker.perform_async(current_user.account_id)
+  end
+
+  def remove_cache
+    redis.del("filtered_statuses:#{current_user.account_id}")
+  end
+
   def user_settings
     UserSettingsDecorator.new(current_user)
   end
@@ -29,8 +44,11 @@ class Settings::PreferencesController < Settings::BaseController
   def user_params
     params.require(:user).permit(
       :locale,
+      :filters_enabled,
       :hide_boosts,
       :only_known,
+      :media_only,
+      :filter_undescribed,
       :invert_filters,
       :filter_timelines_only,
       chosen_languages: []
diff --git a/app/helpers/filter_helper.rb b/app/helpers/filter_helper.rb
index b9dbc1f4f..2334fc356 100644
--- a/app/helpers/filter_helper.rb
+++ b/app/helpers/filter_helper.rb
@@ -1,14 +1,14 @@
 module FilterHelper
   include Redisable
 
-	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?
+	def phrase_filtered?(status, receiver_id, skip_redis: false)
+    return true if !skip_redis && redis.sismember("filtered_statuses:#{receiver_id}", status.id)
+    return false unless CustomFilter.where(account_id: receiver_id, is_enabled: true).exists?
 
     status = status.reblog if status.reblog?
 
     if Status.where(id: status.id).search_filtered_by_account(receiver_id).exists?
-      redis.sadd("filtered_statuses:#{receiver_id}", status.id)
+      redis.sadd("filtered_statuses:#{receiver_id}", status.id) unless skip_redis
       return true
     end
 
diff --git a/app/lib/status_filter.rb b/app/lib/status_filter.rb
index 4cb5804da..dbfa24dfe 100644
--- a/app/lib/status_filter.rb
+++ b/app/lib/status_filter.rb
@@ -15,9 +15,9 @@ class StatusFilter
   def filtered?
     return true if status.nil? || account.nil?
     return false if !account.nil? && account.id == status.account_id
-    return !account.user.invert_filters if !account.user.filter_timelines_only && redis.sismember("filtered_statuses:#{account.id}", status.id)
+    return true if redis.sismember("filtered_statuses:#{account.id}", status.id)
     if blocked_by_policy? || (account_present? && filtered_status?) || silenced_account?
-      redis.sadd("filtered_statuses:#{account.id}", status.id) unless account.user.filter_timelines_only
+      redis.sadd("filtered_statuses:#{account.id}", status.id)
       return true
     end
     false
@@ -40,7 +40,13 @@ class StatusFilter
     return true if account.user_hides_replies_of_blocker? && reply_to_blocker?
 
     # filtered by user?
-    return true if !account.user.filter_timelines_only && !account.user.invert_filters && phrase_filtered?(status, account.id)
+    if account.user.filters_enabled && !account.user.filter_timelines_only
+      if account.user.invert_filters
+        return true unless phrase_filtered?(status, account.id)
+      else
+        return true if phrase_filtered?(status, account.id)
+      end
+    end
 
     # kajiht has no filters if status has no mentions
     return false if status&.mentions.blank?
@@ -74,10 +80,7 @@ class StatusFilter
     return true if !@preloaded_relations[:muting] && account.user_hides_mentions_of_muted? && account.muting?(mentioned_account_ids)
     return true if !@preloaded_relations[:blocking] && account.user_hides_mentions_of_blocked? && account.blocking?(mentioned_account_ids)
     return false unless status.reply? && status.private_visibility? && account.user_hides_mentions_outside_scope?
-    return true if !@preloaded_relations[:following] && (mentioned_account_ids - account.following_ids).any?
-
-    # filtered by user?
-    !account.user.filter_timelines_only && account.user.invert_filters && !phrase_filtered?(status, account.id)
+    !@preloaded_relations[:following] && (mentioned_account_ids - account.following_ids).any?
   end
 
   def reply_to_blocked?
diff --git a/app/models/account.rb b/app/models/account.rb
index 66fe554d5..e43db63bd 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -55,7 +55,6 @@
 #  force_private           :boolean          default(FALSE), not null
 #  unboostable             :boolean          default(FALSE), not null
 #  block_anon              :boolean          default(FALSE), not null
-#  filter_undescribed      :boolean          default(FALSE), not null
 #
 
 class Account < ApplicationRecord
diff --git a/app/models/status.rb b/app/models/status.rb
index 5a1d38932..5d257ba6c 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -119,9 +119,10 @@ class Status < ApplicationRecord
 
   scope :search, ->(needle) { where("tsv @@ websearch_to_tsquery('fedi', ?)", needle) }
   scope :search_not, ->(needle) { where.not("tsv @@ websearch_to_tsquery('fedi', ?)", needle) }
-  scope :search_filtered_by_account, ->(account_id) { where('tsv @@ (SELECT tsquery_union(websearch_to_tsquery(phrase)) FROM custom_filters WHERE account_id = ? AND is_enabled)', account_id) }
-  scope :search_not_filtered_by_account, ->(account_id) { where.not('tsv @@ (SELECT tsquery_union(websearch_to_tsquery(phrase)) FROM custom_filters WHERE account_id = ? AND is_enabled)', account_id) }
+  scope :search_filtered_by_account, ->(account_id) { where("tsv @@ (SELECT tsquery_union(websearch_to_tsquery('fedi', phrase)) FROM custom_filters WHERE account_id = ? AND is_enabled)", account_id) }
+  scope :search_not_filtered_by_account, ->(account_id) { where.not("tsv @@ (SELECT tsquery_union(websearch_to_tsquery('fedi', phrase)) FROM custom_filters WHERE account_id = ? AND is_enabled)", account_id) }
 
+  scope :with_media, -> { joins(:media_attachments).select('statuses.*') }
   scope :not_missing_media_desc, -> { left_outer_joins(:media_attachments).select('statuses.*').where('media_attachments.id IS NULL OR media_attachments.description IS NOT NULL') }
 
   scope :only_followers_of, ->(account) { where(account: [account] + account.following) }
@@ -578,14 +579,15 @@ class Status < ApplicationRecord
       query = query.in_chosen_languages(account) if account.chosen_languages.present?
       query = query.reply_not_excluded_by_account(account) unless tag_timeline
       query = query.mention_not_excluded_by_account(account)
-      unless account.custom_filters.enabled.empty?
+      unless !account.user.filters_enabled || account.custom_filters.enabled.blank?
         if account.user.invert_filters
           query = query.search_filtered_by_account(account.id)
         else
           query = query.search_not_filtered_by_account(account.id)
         end
       end
-      query = query.not_missing_media_desc if account.filter_undescribed?
+      query = query.with_media if account.user.media_only?
+      query = query.not_missing_media_desc if account.user.filter_undescribed?
       query.merge(account_silencing_filter(account))
     end
 
diff --git a/app/models/user.rb b/app/models/user.rb
index 2ee304e81..b519e9b15 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -43,6 +43,9 @@
 #  only_known                :boolean
 #  invert_filters            :boolean          default(FALSE), not null
 #  filter_timelines_only     :boolean          default(FALSE), not null
+#  media_only                :boolean          default(FALSE), not null
+#  filter_undescribed        :boolean          default(FALSE), not null
+#  filters_enabled           :boolean          default(FALSE), not null
 #
 
 class User < ApplicationRecord
diff --git a/app/views/settings/preferences/show.html.haml b/app/views/settings/preferences/show.html.haml
index 80ad6c109..fdb5fea3f 100644
--- a/app/views/settings/preferences/show.html.haml
+++ b/app/views/settings/preferences/show.html.haml
@@ -11,48 +11,62 @@
 = simple_form_for current_user, url: settings_preferences_path, html: { method: :put } do |f|
   = render 'shared/error_messages', object: current_user
 
-  .fields-row#settings_languages
-    .fields-group.fields-row__column.fields-row__column-6
-      = f.input :locale, collection: I18n.available_locales, wrapper: :with_label, include_blank: false, label_method: lambda { |locale| human_locale(locale) }, selected: I18n.locale
-    .fields-group.fields-row__column.fields-row__column-6
-      = f.input :setting_default_language, collection: [nil] + filterable_languages.sort, wrapper: :with_label, label_method: lambda { |locale| locale.nil? ? I18n.t('statuses.language_detection') : human_locale(locale) }, required: false, include_blank: false
-
-  .fields-group
-    = f.input :chosen_languages, collection: filterable_languages.sort, wrapper: :with_block_label, include_blank: false, label_method: lambda { |locale| human_locale(locale) }, required: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
-
   %hr#settings_publishing/
 
   .fields-group
     = f.input :setting_default_privacy, collection: Status.selectable_visibilities, wrapper: :with_floating_label, include_blank: false, label_method: lambda { |visibility| safe_join([I18n.t("statuses.visibilities.#{visibility}"), content_tag(:span, I18n.t("statuses.visibilities.#{visibility}_long"), class: 'hint')]) }, required: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
 
-    = f.input :setting_default_content_type, collection: ['text/x-bbcode+markdown', 'text/markdown', 'text/x-bbcode', 'text/html', 'text/plain', 'text/console'], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.defaults.setting_default_content_type_#{item.split('/')[1].gsub(/[+-]/, '_')}"), content_tag(:span, t("simple_form.hints.defaults.setting_default_content_type_#{item.split('/')[1].gsub(/[+-]/, '_')}_html"), class: 'hint')]) }, required: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
-
+  .fields-group
+    = f.input :setting_max_public_history, collection: [1, 3, 6, 7, 14, 30, 60, 90, 180, 365, 730, 1095, 2190], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.lifespan.#{item}")]) }, selected: current_user.max_public_history
+    = f.input :setting_roar_lifespan, collection: [0, 1, 3, 6, 7, 14, 30, 60, 90, 180, 365, 730, 1095, 2190], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.lifespan.#{item}")]) }, selected: current_user.roar_lifespan
 
   .fields-group
+    = f.input :setting_default_sensitive, as: :boolean, wrapper: :with_label
     = f.input :setting_default_local, as: :boolean, wrapper: :with_label
     = f.input :setting_always_local, as: :boolean, wrapper: :with_label
-    = f.input :setting_default_sensitive, as: :boolean, wrapper: :with_label
+    = f.input :setting_hide_public_profile, as: :boolean, wrapper: :with_label
+    = f.input :setting_hide_public_outbox, as: :boolean, wrapper: :with_label
+
+  %hr/
+
+  .fields-group
+    = f.input :setting_default_content_type, collection: ['text/x-bbcode+markdown', 'text/markdown', 'text/x-bbcode', 'text/html', 'text/plain', 'text/console'], wrapper: :with_floating_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.defaults.setting_default_content_type_#{item.split('/')[1].gsub(/[+-]/, '_')}"), content_tag(:span, t("simple_form.hints.defaults.setting_default_content_type_#{item.split('/')[1].gsub(/[+-]/, '_')}_html"), class: 'hint')]) }, required: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
+
+  %hr/
 
   .fields-group
     = f.input :setting_delayed_roars, as: :boolean, wrapper: :with_label
     = f.input :setting_delayed_for, collection: [5, 10, 15, 30, 60, 120, 180, 300, 360, 600, 1800, 3600], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.delayed_for.#{item}")]) }, selected: current_user.delayed_for
 
+  %hr/
+
   .fields-group
     = f.input :setting_boost_interval, as: :boolean, wrapper: :with_label
     = f.input :setting_boost_random, as: :boolean, wrapper: :with_label
     = f.input :setting_boost_interval_from, collection: [1, 2, 3, 4, 5, 6, 10, 15, 30, 60, 120, 180, 300, 360, 720, 1440], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.boost_interval.#{item}")]) }, selected: current_user.boost_interval_from
     = f.input :setting_boost_interval_to, collection: [1, 2, 3, 4, 5, 6, 10, 15, 30, 60, 120, 180, 300, 360, 720, 1440], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.boost_interval.#{item}")]) }, selected: current_user.boost_interval_to
 
+
+
+
   %hr#settings_other/
 
   .fields-group
+    = f.input :filters_enabled, as: :boolean, wrapper: :with_label
     = f.input :invert_filters, as: :boolean, wrapper: :with_label
     = f.input :filter_timelines_only, as: :boolean, wrapper: :with_label
+    = f.input :setting_filter_mentions, as: :boolean, wrapper: :with_label
+
+  %hr/
 
   .fields-group
-    = f.input :setting_rawr_federated, as: :boolean, wrapper: :with_label
-    = f.input :hide_boosts, as: :boolean, wrapper: :with_label
     = f.input :only_known, as: :boolean, wrapper: :with_label
+    = f.input :hide_boosts, as: :boolean, wrapper: :with_label
+    = f.input :media_only, as: :boolean, wrapper: :with_label
+    = f.input :filter_undescribed, as: :boolean, wrapper: :with_label
+
+  .fields-group
+    = f.input :setting_rawr_federated, as: :boolean, wrapper: :with_label
 
   %hr/
 
@@ -63,14 +77,6 @@
     = f.input :setting_show_application, as: :boolean, wrapper: :with_label
     = f.input :setting_noindex, as: :boolean, wrapper: :with_label
 
-  %hr/
-
-  .fields-group
-    = f.input :setting_max_public_history, collection: [1, 3, 6, 7, 14, 30, 60, 90, 180, 365, 730, 1095, 2190], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.lifespan.#{item}")]) }, selected: current_user.max_public_history
-    = f.input :setting_roar_lifespan, collection: [0, 1, 3, 6, 7, 14, 30, 60, 90, 180, 365, 730, 1095, 2190], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.lifespan.#{item}")]) }, selected: current_user.roar_lifespan
-    = f.input :setting_hide_public_profile, as: :boolean, wrapper: :with_label
-    = f.input :setting_hide_public_outbox, as: :boolean, wrapper: :with_label
-
   - unless Setting.hide_followers_count
     .fields-group
       = f.input :setting_hide_followers_count, as: :boolean, wrapper: :with_label
@@ -91,7 +97,6 @@
 
   .fields-group
     = f.input :setting_hide_mascot, as: :boolean, wrapper: :with_label
-    = f.input :setting_filter_mentions, as: :boolean, wrapper: :with_label
     = f.input :setting_hide_replies_muted, as: :boolean, wrapper: :with_label
     = f.input :setting_hide_replies_blocked, as: :boolean, wrapper: :with_label
     = f.input :setting_hide_replies_blocker, as: :boolean, wrapper: :with_label
@@ -116,5 +121,14 @@
     = f.input :setting_display_media, collection: ['default', 'show_all', 'hide_all'], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.defaults.setting_display_media_#{item}"), content_tag(:span, t("simple_form.hints.defaults.setting_display_media_#{item}"), class: 'hint')]) }, required: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
     = f.input :setting_expand_spoilers, as: :boolean, wrapper: :with_label
 
+  .fields-row#settings_languages
+    .fields-group.fields-row__column.fields-row__column-6
+      = f.input :locale, collection: I18n.available_locales, wrapper: :with_label, include_blank: false, label_method: lambda { |locale| human_locale(locale) }, selected: I18n.locale
+    .fields-group.fields-row__column.fields-row__column-6
+      = f.input :setting_default_language, collection: [nil] + filterable_languages.sort, wrapper: :with_label, label_method: lambda { |locale| locale.nil? ? I18n.t('statuses.language_detection') : human_locale(locale) }, required: false, include_blank: false
+
+  .fields-group
+    = f.input :chosen_languages, collection: filterable_languages.sort, wrapper: :with_block_label, include_blank: false, label_method: lambda { |locale| human_locale(locale) }, required: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
+
   .actions
     = f.button :button, t('generic.save_changes'), type: :submit
diff --git a/app/views/settings/profiles/show.html.haml b/app/views/settings/profiles/show.html.haml
index 35135267c..4fabfb9f4 100644
--- a/app/views/settings/profiles/show.html.haml
+++ b/app/views/settings/profiles/show.html.haml
@@ -43,11 +43,6 @@
 
   %hr.spacer/
 
-  .fields-group
-    = f.input :filter_undescribed, as: :boolean, wrapper: :with_label
-
-  %hr.spacer/
-
   .fields-row
     .fields-row__column.fields-group.fields-row__column-6
       .input.with_block_label