commit
						a2612d0d38
					
				
							
								
								
									
										64
									
								
								app/controllers/settings/keyword_mutes_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								app/controllers/settings/keyword_mutes_controller.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | |||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | class Settings::KeywordMutesController < ApplicationController | ||||||
|  |   layout 'admin' | ||||||
|  | 
 | ||||||
|  |   before_action :authenticate_user! | ||||||
|  |   before_action :load_keyword_mute, only: [:edit, :update, :destroy] | ||||||
|  | 
 | ||||||
|  |   def index | ||||||
|  |     @keyword_mutes = paginated_keyword_mutes_for_account | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def new | ||||||
|  |     @keyword_mute = keyword_mutes_for_account.build | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def create | ||||||
|  |     @keyword_mute = keyword_mutes_for_account.create(keyword_mute_params) | ||||||
|  | 
 | ||||||
|  |     if @keyword_mute.persisted? | ||||||
|  |       redirect_to settings_keyword_mutes_path, notice: I18n.t('generic.changes_saved_msg') | ||||||
|  |     else | ||||||
|  |       render :new | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def update | ||||||
|  |     if @keyword_mute.update(keyword_mute_params) | ||||||
|  |       redirect_to settings_keyword_mutes_path, notice: I18n.t('generic.changes_saved_msg') | ||||||
|  |     else | ||||||
|  |       render :edit | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def destroy | ||||||
|  |     @keyword_mute.destroy! | ||||||
|  | 
 | ||||||
|  |     redirect_to settings_keyword_mutes_path, notice: I18n.t('generic.changes_saved_msg') | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def destroy_all | ||||||
|  |     keyword_mutes_for_account.delete_all | ||||||
|  | 
 | ||||||
|  |     redirect_to settings_keyword_mutes_path, notice: I18n.t('generic.changes_saved_msg') | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   private | ||||||
|  | 
 | ||||||
|  |   def keyword_mutes_for_account | ||||||
|  |     Glitch::KeywordMute.where(account: current_account) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def load_keyword_mute | ||||||
|  |     @keyword_mute = keyword_mutes_for_account.find(params[:id]) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def keyword_mute_params | ||||||
|  |     params.require(:keyword_mute).permit(:keyword, :whole_word) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def paginated_keyword_mutes_for_account | ||||||
|  |     keyword_mutes_for_account.order(:keyword).page params[:page] | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										2
									
								
								app/helpers/settings/keyword_mutes_helper.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								app/helpers/settings/keyword_mutes_helper.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | |||||||
|  | module Settings::KeywordMutesHelper | ||||||
|  | end | ||||||
| @ -141,6 +141,8 @@ class FeedManager | |||||||
|     return false if receiver_id == status.account_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 status.reply? && (status.in_reply_to_id.nil? || status.in_reply_to_account_id.nil?) | ||||||
| 
 | 
 | ||||||
|  |     return true if keyword_filter?(status, Glitch::KeywordMute.matcher_for(receiver_id)) | ||||||
|  | 
 | ||||||
|     check_for_mutes = [status.account_id] |     check_for_mutes = [status.account_id] | ||||||
|     check_for_mutes.concat(status.mentions.pluck(:account_id)) |     check_for_mutes.concat(status.mentions.pluck(:account_id)) | ||||||
|     check_for_mutes.concat([status.reblog.account_id]) if status.reblog? |     check_for_mutes.concat([status.reblog.account_id]) if status.reblog? | ||||||
| @ -166,6 +168,18 @@ class FeedManager | |||||||
|     false |     false | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   def keyword_filter?(status, matcher) | ||||||
|  |     should_filter   = matcher =~ status.text | ||||||
|  |     should_filter ||= matcher =~ status.spoiler_text | ||||||
|  | 
 | ||||||
|  |     if status.reblog? | ||||||
|  |       should_filter ||= matcher =~ status.reblog.text | ||||||
|  |       should_filter ||= matcher =~ status.reblog.spoiler_text | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     !!should_filter | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   def filter_from_mentions?(status, receiver_id) |   def filter_from_mentions?(status, receiver_id) | ||||||
|     return true if receiver_id == status.account_id |     return true if receiver_id == status.account_id | ||||||
| 
 | 
 | ||||||
| @ -175,6 +189,7 @@ class FeedManager | |||||||
| 
 | 
 | ||||||
|     should_filter   = Block.where(account_id: receiver_id, target_account_id: check_for_blocks).any?                                     # Filter if it's from someone I blocked, in reply to someone I blocked, or mentioning someone I blocked |     should_filter   = Block.where(account_id: receiver_id, target_account_id: check_for_blocks).any?                                     # Filter if it's from someone I blocked, in reply to someone I blocked, or mentioning someone I blocked | ||||||
|     should_filter ||= (status.account.silenced? && !Follow.where(account_id: receiver_id, target_account_id: status.account_id).exists?) # of if the account is silenced and I'm not following them |     should_filter ||= (status.account.silenced? && !Follow.where(account_id: receiver_id, target_account_id: status.account_id).exists?) # of if the account is silenced and I'm not following them | ||||||
|  |     should_filter ||= keyword_filter?(status, Glitch::KeywordMute.matcher_for(receiver_id))                                              # or if the mention contains a muted keyword | ||||||
| 
 | 
 | ||||||
|     should_filter |     should_filter | ||||||
|   end |   end | ||||||
|  | |||||||
							
								
								
									
										7
									
								
								app/models/glitch.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/models/glitch.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | module Glitch | ||||||
|  |   def self.table_name_prefix | ||||||
|  |     'glitch_' | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										66
									
								
								app/models/glitch/keyword_mute.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								app/models/glitch/keyword_mute.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,66 @@ | |||||||
|  | # frozen_string_literal: true | ||||||
|  | # == Schema Information | ||||||
|  | # | ||||||
|  | # Table name: glitch_keyword_mutes | ||||||
|  | # | ||||||
|  | #  id         :integer          not null, primary key | ||||||
|  | #  account_id :integer          not null | ||||||
|  | #  keyword    :string           not null | ||||||
|  | #  whole_word :boolean          default(TRUE), not null | ||||||
|  | #  created_at :datetime         not null | ||||||
|  | #  updated_at :datetime         not null | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | class Glitch::KeywordMute < ApplicationRecord | ||||||
|  |   belongs_to :account, required: true | ||||||
|  | 
 | ||||||
|  |   validates_presence_of :keyword | ||||||
|  | 
 | ||||||
|  |   after_commit :invalidate_cached_matcher | ||||||
|  | 
 | ||||||
|  |   def self.matcher_for(account_id) | ||||||
|  |     Matcher.new(account_id) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   private | ||||||
|  | 
 | ||||||
|  |   def invalidate_cached_matcher | ||||||
|  |     Rails.cache.delete("keyword_mutes:regex:#{account_id}") | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   class Matcher | ||||||
|  |     attr_reader :account_id | ||||||
|  |     attr_reader :regex | ||||||
|  | 
 | ||||||
|  |     def initialize(account_id) | ||||||
|  |       @account_id = account_id | ||||||
|  |       regex_text = Rails.cache.fetch("keyword_mutes:regex:#{account_id}") { regex_text_for_account } | ||||||
|  |       @regex = /#{regex_text}/i | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def =~(str) | ||||||
|  |       regex =~ str | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     private | ||||||
|  | 
 | ||||||
|  |     def keywords | ||||||
|  |       Glitch::KeywordMute.where(account_id: account_id).select(:keyword, :id, :whole_word) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def regex_text_for_account | ||||||
|  |       kws = keywords.find_each.with_object([]) do |kw, a| | ||||||
|  |         a << (kw.whole_word ? boundary_regex_for_keyword(kw.keyword) : kw.keyword) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       Regexp.union(kws).source | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def boundary_regex_for_keyword(keyword) | ||||||
|  |       sb = keyword =~ /\A[[:word:]]/ ? '\b' : '' | ||||||
|  |       eb = keyword =~ /[[:word:]]\Z/ ? '\b' : '' | ||||||
|  | 
 | ||||||
|  |       /#{sb}#{Regexp.escape(keyword)}#{eb}/ | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										11
									
								
								app/views/settings/keyword_mutes/_fields.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/views/settings/keyword_mutes/_fields.html.haml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | .fields-group | ||||||
|  |   = f.input :keyword | ||||||
|  |   = f.check_box :whole_word | ||||||
|  |   = f.label :whole_word, t('keyword_mutes.match_whole_word') | ||||||
|  | 
 | ||||||
|  | .actions | ||||||
|  |   - if f.object.persisted? | ||||||
|  |     = f.button :button, t('generic.save_changes'), type: :submit | ||||||
|  |     = link_to t('keyword_mutes.remove'), settings_keyword_mute_path(f.object), class: 'negative button', method: :delete, data: { confirm: t('admin.accounts.are_you_sure') } | ||||||
|  |   - else | ||||||
|  |     = f.button :button, t('keyword_mutes.add_keyword'), type: :submit | ||||||
							
								
								
									
										10
									
								
								app/views/settings/keyword_mutes/_keyword_mute.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/views/settings/keyword_mutes/_keyword_mute.html.haml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | %tr | ||||||
|  |   %td | ||||||
|  |     = keyword_mute.keyword | ||||||
|  |   %td | ||||||
|  |     - if keyword_mute.whole_word | ||||||
|  |       %i.fa.fa-check | ||||||
|  |   %td | ||||||
|  |     = table_link_to 'edit', t('keyword_mutes.edit'), edit_settings_keyword_mute_path(keyword_mute) | ||||||
|  |   %td | ||||||
|  |     = table_link_to 'times', t('keyword_mutes.remove'), settings_keyword_mute_path(keyword_mute), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') } | ||||||
							
								
								
									
										6
									
								
								app/views/settings/keyword_mutes/edit.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								app/views/settings/keyword_mutes/edit.html.haml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | - content_for :page_title do | ||||||
|  |   = t('keyword_mutes.edit_keyword') | ||||||
|  | 
 | ||||||
|  | = simple_form_for @keyword_mute, url: settings_keyword_mute_path(@keyword_mute), as: :keyword_mute do |f| | ||||||
|  |   = render 'shared/error_messages', object: @keyword_mute | ||||||
|  |   = render 'fields', f: f | ||||||
							
								
								
									
										18
									
								
								app/views/settings/keyword_mutes/index.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								app/views/settings/keyword_mutes/index.html.haml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | - content_for :page_title do | ||||||
|  |   = t('settings.keyword_mutes') | ||||||
|  | 
 | ||||||
|  | .table-wrapper | ||||||
|  |   %table.table | ||||||
|  |     %thead | ||||||
|  |       %tr | ||||||
|  |         %th= t('keyword_mutes.keyword') | ||||||
|  |         %th= t('keyword_mutes.match_whole_word') | ||||||
|  |         %th | ||||||
|  |         %th | ||||||
|  |       %tbody | ||||||
|  |         = render partial: 'keyword_mute', collection: @keyword_mutes, as: :keyword_mute | ||||||
|  | 
 | ||||||
|  | = paginate @keyword_mutes | ||||||
|  | .simple_form | ||||||
|  |   = link_to t('keyword_mutes.add_keyword'), new_settings_keyword_mute_path, class: 'button' | ||||||
|  |   = link_to t('keyword_mutes.remove_all'), destroy_all_settings_keyword_mutes_path, class: 'button negative', method: :delete, data: { confirm: t('admin.accounts.are_you_sure') } | ||||||
							
								
								
									
										6
									
								
								app/views/settings/keyword_mutes/new.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								app/views/settings/keyword_mutes/new.html.haml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | - content_for :page_title do | ||||||
|  |   = t('keyword_mutes.add_keyword') | ||||||
|  | 
 | ||||||
|  | = simple_form_for @keyword_mute, url: settings_keyword_mutes_path, as: :keyword_mute do |f| | ||||||
|  |   = render 'shared/error_messages', object: @keyword_mute | ||||||
|  |   = render 'fields', f: f | ||||||
| @ -373,6 +373,14 @@ en: | |||||||
|       following: Following list |       following: Following list | ||||||
|       muting: Muting list |       muting: Muting list | ||||||
|     upload: Upload |     upload: Upload | ||||||
|  |   keyword_mutes: | ||||||
|  |     add_keyword: Add keyword | ||||||
|  |     edit: Edit | ||||||
|  |     edit_keyword: Edit keyword | ||||||
|  |     keyword: Keyword | ||||||
|  |     match_whole_word: Match whole word | ||||||
|  |     remove: Remove | ||||||
|  |     remove_all: Remove all | ||||||
|   landing_strip_html: "<strong>%{name}</strong> is a user on %{link_to_root_path}. You can follow them or interact with them if you have an account anywhere in the fediverse." |   landing_strip_html: "<strong>%{name}</strong> is a user on %{link_to_root_path}. You can follow them or interact with them if you have an account anywhere in the fediverse." | ||||||
|   landing_strip_signup_html: If you don't, you can <a href="%{sign_up_path}">sign up here</a>. |   landing_strip_signup_html: If you don't, you can <a href="%{sign_up_path}">sign up here</a>. | ||||||
|   media_attachments: |   media_attachments: | ||||||
| @ -491,6 +499,7 @@ en: | |||||||
|     export: Data export |     export: Data export | ||||||
|     followers: Authorized followers |     followers: Authorized followers | ||||||
|     import: Import |     import: Import | ||||||
|  |     keyword_mutes: Muted keywords | ||||||
|     notifications: Notifications |     notifications: Notifications | ||||||
|     preferences: Preferences |     preferences: Preferences | ||||||
|     settings: Settings |     settings: Settings | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ SimpleNavigation::Configuration.run do |navigation| | |||||||
|     primary.item :settings, safe_join([fa_icon('cog fw'), t('settings.settings')]), settings_profile_url do |settings| |     primary.item :settings, safe_join([fa_icon('cog fw'), t('settings.settings')]), settings_profile_url do |settings| | ||||||
|       settings.item :profile, safe_join([fa_icon('user fw'), t('settings.edit_profile')]), settings_profile_url |       settings.item :profile, safe_join([fa_icon('user fw'), t('settings.edit_profile')]), settings_profile_url | ||||||
|       settings.item :preferences, safe_join([fa_icon('sliders fw'), t('settings.preferences')]), settings_preferences_url |       settings.item :preferences, safe_join([fa_icon('sliders fw'), t('settings.preferences')]), settings_preferences_url | ||||||
|  |       settings.item :keyword_mutes, safe_join([fa_icon('volume-off fw'), t('settings.keyword_mutes')]), settings_keyword_mutes_url | ||||||
|       settings.item :notifications, safe_join([fa_icon('bell fw'), t('settings.notifications')]), settings_notifications_url |       settings.item :notifications, safe_join([fa_icon('bell fw'), t('settings.notifications')]), settings_notifications_url | ||||||
|       settings.item :password, safe_join([fa_icon('lock fw'), t('auth.change_password')]), edit_user_registration_url, highlights_on: %r{/auth/edit|/settings/delete} |       settings.item :password, safe_join([fa_icon('lock fw'), t('auth.change_password')]), edit_user_registration_url, highlights_on: %r{/auth/edit|/settings/delete} | ||||||
|       settings.item :two_factor_authentication, safe_join([fa_icon('mobile fw'), t('settings.two_factor_authentication')]), settings_two_factor_authentication_url, highlights_on: %r{/settings/two_factor_authentication} |       settings.item :two_factor_authentication, safe_join([fa_icon('mobile fw'), t('settings.two_factor_authentication')]), settings_two_factor_authentication_url, highlights_on: %r{/settings/two_factor_authentication} | ||||||
|  | |||||||
| @ -66,6 +66,13 @@ Rails.application.routes.draw do | |||||||
| 
 | 
 | ||||||
|   namespace :settings do |   namespace :settings do | ||||||
|     resource :profile, only: [:show, :update] |     resource :profile, only: [:show, :update] | ||||||
|  | 
 | ||||||
|  |     resources :keyword_mutes do | ||||||
|  |       collection do | ||||||
|  |         delete :destroy_all | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|     resource :preferences, only: [:show, :update] |     resource :preferences, only: [:show, :update] | ||||||
|     resource :notifications, only: [:show, :update] |     resource :notifications, only: [:show, :update] | ||||||
|     resource :import, only: [:show, :create] |     resource :import, only: [:show, :create] | ||||||
|  | |||||||
							
								
								
									
										12
									
								
								db/migrate/20171009222537_create_keyword_mutes.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								db/migrate/20171009222537_create_keyword_mutes.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | class CreateKeywordMutes < ActiveRecord::Migration[5.1] | ||||||
|  |   def change | ||||||
|  |     create_table :keyword_mutes do |t| | ||||||
|  |       t.references :account, null: false | ||||||
|  |       t.string :keyword, null: false | ||||||
|  |       t.boolean :whole_word, null: false, default: true | ||||||
|  |       t.timestamps | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     add_foreign_key :keyword_mutes, :accounts, on_delete: :cascade | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -0,0 +1,7 @@ | |||||||
|  | class MoveKeywordMutesIntoGlitchNamespace < ActiveRecord::Migration[5.1] | ||||||
|  |   def change | ||||||
|  |     safety_assured do | ||||||
|  |       rename_table :keyword_mutes, :glitch_keyword_mutes | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										12
									
								
								db/schema.rb
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								db/schema.rb
									
									
									
									
									
								
							| @ -10,7 +10,7 @@ | |||||||
| # | # | ||||||
| # It's strongly recommended that you check this file into your version control system. | # It's strongly recommended that you check this file into your version control system. | ||||||
| 
 | 
 | ||||||
| ActiveRecord::Schema.define(version: 20171010025614) do | ActiveRecord::Schema.define(version: 20171021191900) do | ||||||
| 
 | 
 | ||||||
|   # These are extensions that must be enabled in order to support this database |   # These are extensions that must be enabled in order to support this database | ||||||
|   enable_extension "plpgsql" |   enable_extension "plpgsql" | ||||||
| @ -155,6 +155,15 @@ ActiveRecord::Schema.define(version: 20171010025614) do | |||||||
|     t.index ["account_id", "target_account_id"], name: "index_follows_on_account_id_and_target_account_id", unique: true |     t.index ["account_id", "target_account_id"], name: "index_follows_on_account_id_and_target_account_id", unique: true | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   create_table "glitch_keyword_mutes", force: :cascade do |t| | ||||||
|  |     t.bigint "account_id", null: false | ||||||
|  |     t.string "keyword", null: false | ||||||
|  |     t.boolean "whole_word", default: true, null: false | ||||||
|  |     t.datetime "created_at", null: false | ||||||
|  |     t.datetime "updated_at", null: false | ||||||
|  |     t.index ["account_id"], name: "index_glitch_keyword_mutes_on_account_id" | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   create_table "imports", force: :cascade do |t| |   create_table "imports", force: :cascade do |t| | ||||||
|     t.integer "type", null: false |     t.integer "type", null: false | ||||||
|     t.boolean "approved", default: false, null: false |     t.boolean "approved", default: false, null: false | ||||||
| @ -472,6 +481,7 @@ ActiveRecord::Schema.define(version: 20171010025614) do | |||||||
|   add_foreign_key "follow_requests", "accounts", name: "fk_76d644b0e7", on_delete: :cascade |   add_foreign_key "follow_requests", "accounts", name: "fk_76d644b0e7", on_delete: :cascade | ||||||
|   add_foreign_key "follows", "accounts", column: "target_account_id", name: "fk_745ca29eac", on_delete: :cascade |   add_foreign_key "follows", "accounts", column: "target_account_id", name: "fk_745ca29eac", on_delete: :cascade | ||||||
|   add_foreign_key "follows", "accounts", name: "fk_32ed1b5560", on_delete: :cascade |   add_foreign_key "follows", "accounts", name: "fk_32ed1b5560", on_delete: :cascade | ||||||
|  |   add_foreign_key "glitch_keyword_mutes", "accounts", on_delete: :cascade | ||||||
|   add_foreign_key "imports", "accounts", name: "fk_6db1b6e408", on_delete: :cascade |   add_foreign_key "imports", "accounts", name: "fk_6db1b6e408", on_delete: :cascade | ||||||
|   add_foreign_key "media_attachments", "accounts", name: "fk_96dd81e81b", on_delete: :nullify |   add_foreign_key "media_attachments", "accounts", name: "fk_96dd81e81b", on_delete: :nullify | ||||||
|   add_foreign_key "media_attachments", "statuses", on_delete: :nullify |   add_foreign_key "media_attachments", "statuses", on_delete: :nullify | ||||||
|  | |||||||
| @ -0,0 +1,5 @@ | |||||||
|  | require 'rails_helper' | ||||||
|  | 
 | ||||||
|  | RSpec.describe Settings::KeywordMutesController, type: :controller do | ||||||
|  | 
 | ||||||
|  | end | ||||||
							
								
								
									
										2
									
								
								spec/fabricators/glitch_keyword_mute_fabricator.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								spec/fabricators/glitch_keyword_mute_fabricator.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | |||||||
|  | Fabricator('Glitch::KeywordMute') do | ||||||
|  | end | ||||||
							
								
								
									
										15
									
								
								spec/helpers/settings/keyword_mutes_helper_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								spec/helpers/settings/keyword_mutes_helper_spec.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | require 'rails_helper' | ||||||
|  | 
 | ||||||
|  | # Specs in this file have access to a helper object that includes | ||||||
|  | # the Settings::KeywordMutesHelper. For example: | ||||||
|  | # | ||||||
|  | # describe Settings::KeywordMutesHelper do | ||||||
|  | #   describe "string concat" do | ||||||
|  | #     it "concats two strings with spaces" do | ||||||
|  | #       expect(helper.concat_strings("this","that")).to eq("this that") | ||||||
|  | #     end | ||||||
|  | #   end | ||||||
|  | # end | ||||||
|  | RSpec.describe Settings::KeywordMutesHelper, type: :helper do | ||||||
|  |   pending "add some examples to (or delete) #{__FILE__}" | ||||||
|  | end | ||||||
| @ -119,6 +119,44 @@ RSpec.describe FeedManager do | |||||||
|         reblog = Fabricate(:status, reblog: status, account: jeff) |         reblog = Fabricate(:status, reblog: status, account: jeff) | ||||||
|         expect(FeedManager.instance.filter?(:home, reblog, alice.id)).to be true |         expect(FeedManager.instance.filter?(:home, reblog, alice.id)).to be true | ||||||
|       end |       end | ||||||
|  | 
 | ||||||
|  |       it 'returns true for a status containing a muted keyword' do | ||||||
|  |         Fabricate('Glitch::KeywordMute', account: alice, keyword: 'take') | ||||||
|  |         status = Fabricate(:status, text: 'This is a hot take', account: bob) | ||||||
|  | 
 | ||||||
|  |         expect(FeedManager.instance.filter?(:home, status, alice.id)).to be true | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'returns true for a reply containing a muted keyword' do | ||||||
|  |         Fabricate('Glitch::KeywordMute', account: alice, keyword: 'take') | ||||||
|  |         s1 = Fabricate(:status, text: 'Something', account: alice) | ||||||
|  |         s2 = Fabricate(:status, text: 'This is a hot take', thread: s1, account: bob) | ||||||
|  | 
 | ||||||
|  |         expect(FeedManager.instance.filter?(:home, s2, alice.id)).to be true | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'returns true for a status whose spoiler text contains a muted keyword' do | ||||||
|  |         Fabricate('Glitch::KeywordMute', account: alice, keyword: 'take') | ||||||
|  |         status = Fabricate(:status, spoiler_text: 'This is a hot take', account: bob) | ||||||
|  | 
 | ||||||
|  |         expect(FeedManager.instance.filter?(:home, status, alice.id)).to be true | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'returns true for a reblog containing a muted keyword' do | ||||||
|  |         Fabricate('Glitch::KeywordMute', account: alice, keyword: 'take') | ||||||
|  |         status = Fabricate(:status, text: 'This is a hot take', account: bob) | ||||||
|  |         reblog = Fabricate(:status, reblog: status, account: jeff) | ||||||
|  | 
 | ||||||
|  |         expect(FeedManager.instance.filter?(:home, reblog, alice.id)).to be true | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'returns true for a reblog whose spoiler text contains a muted keyword' do | ||||||
|  |         Fabricate('Glitch::KeywordMute', account: alice, keyword: 'take') | ||||||
|  |         status = Fabricate(:status, spoiler_text: 'This is a hot take', account: bob) | ||||||
|  |         reblog = Fabricate(:status, reblog: status, account: jeff) | ||||||
|  | 
 | ||||||
|  |         expect(FeedManager.instance.filter?(:home, reblog, alice.id)).to be true | ||||||
|  |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     context 'for mentions feed' do |     context 'for mentions feed' do | ||||||
| @ -147,6 +185,13 @@ RSpec.describe FeedManager do | |||||||
|         bob.follow!(alice) |         bob.follow!(alice) | ||||||
|         expect(FeedManager.instance.filter?(:mentions, status, bob.id)).to be false |         expect(FeedManager.instance.filter?(:mentions, status, bob.id)).to be false | ||||||
|       end |       end | ||||||
|  | 
 | ||||||
|  |       it 'returns true for status that contains a muted keyword' do | ||||||
|  |         Fabricate('Glitch::KeywordMute', account: bob, keyword: 'take') | ||||||
|  |         status = Fabricate(:status, text: 'This is a hot take', account: alice) | ||||||
|  |         bob.follow!(alice) | ||||||
|  |         expect(FeedManager.instance.filter?(:mentions, status, bob.id)).to be true | ||||||
|  |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										89
									
								
								spec/models/glitch/keyword_mute_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								spec/models/glitch/keyword_mute_spec.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,89 @@ | |||||||
|  | require 'rails_helper' | ||||||
|  | 
 | ||||||
|  | RSpec.describe Glitch::KeywordMute, type: :model do | ||||||
|  |   let(:alice) { Fabricate(:account, username: 'alice').tap(&:save!) } | ||||||
|  |   let(:bob) { Fabricate(:account, username: 'bob').tap(&:save!) } | ||||||
|  | 
 | ||||||
|  |   describe '.matcher_for' do | ||||||
|  |     let(:matcher) { Glitch::KeywordMute.matcher_for(alice) } | ||||||
|  | 
 | ||||||
|  |     describe 'with no mutes' do | ||||||
|  |       before do | ||||||
|  |         Glitch::KeywordMute.delete_all | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'does not match' do | ||||||
|  |         expect(matcher =~ 'This is a hot take').to be_falsy | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     describe 'with mutes' do | ||||||
|  |       it 'does not match keywords set by a different account' do | ||||||
|  |         Glitch::KeywordMute.create!(account: bob, keyword: 'take') | ||||||
|  | 
 | ||||||
|  |         expect(matcher =~ 'This is a hot take').to be_falsy | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'does not match if no keywords match the status text' do | ||||||
|  |         Glitch::KeywordMute.create!(account: alice, keyword: 'cold') | ||||||
|  | 
 | ||||||
|  |         expect(matcher =~ 'This is a hot take').to be_falsy | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'considers word boundaries when matching' do | ||||||
|  |         Glitch::KeywordMute.create!(account: alice, keyword: 'bob', whole_word: true) | ||||||
|  | 
 | ||||||
|  |         expect(matcher =~ 'bobcats').to be_falsy | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'matches substrings if whole_word is false' do | ||||||
|  |         Glitch::KeywordMute.create!(account: alice, keyword: 'take', whole_word: false) | ||||||
|  | 
 | ||||||
|  |         expect(matcher =~ 'This is a shiitake mushroom').to be_truthy | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'matches keywords at the beginning of the text' do | ||||||
|  |         Glitch::KeywordMute.create!(account: alice, keyword: 'take') | ||||||
|  | 
 | ||||||
|  |         expect(matcher =~ 'Take this').to be_truthy | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'matches keywords at the end of the text' do | ||||||
|  |         Glitch::KeywordMute.create!(account: alice, keyword: 'take') | ||||||
|  | 
 | ||||||
|  |         expect(matcher =~ 'This is a hot take').to be_truthy | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'matches if at least one keyword case-insensitively matches the text' do | ||||||
|  |         Glitch::KeywordMute.create!(account: alice, keyword: 'hot') | ||||||
|  | 
 | ||||||
|  |         expect(matcher =~ 'This is a HOT take').to be_truthy | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'matches keywords surrounded by non-alphanumeric ornamentation' do | ||||||
|  |         Glitch::KeywordMute.create!(account: alice, keyword: 'hot') | ||||||
|  | 
 | ||||||
|  |         expect(matcher =~ '(hot take)').to be_truthy | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'escapes metacharacters in keywords' do | ||||||
|  |         Glitch::KeywordMute.create!(account: alice, keyword: '(hot take)') | ||||||
|  | 
 | ||||||
|  |         expect(matcher =~ '(hot take)').to be_truthy | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'uses case-folding rules appropriate for more than just English' do | ||||||
|  |         Glitch::KeywordMute.create!(account: alice, keyword: 'großeltern') | ||||||
|  | 
 | ||||||
|  |         expect(matcher =~ 'besuch der grosseltern').to be_truthy | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'matches keywords that are composed of multiple words' do | ||||||
|  |         Glitch::KeywordMute.create!(account: alice, keyword: 'a shiitake') | ||||||
|  | 
 | ||||||
|  |         expect(matcher =~ 'This is a shiitake').to be_truthy | ||||||
|  |         expect(matcher =~ 'This is shiitake').to_not be_truthy | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user