about summary refs log tree commit diff
path: root/app/models/custom_filter.rb
blob: 8df8a4fbf3bd1833a197657424c6229dd7ea9040 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# frozen_string_literal: true
# == Schema Information
#
# 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
#  whole_word   :boolean          default(TRUE), not null
#  irreversible :boolean          default(FALSE), not null
#  created_at   :datetime         not null
#  updated_at   :datetime         not null
#

class CustomFilter < ApplicationRecord
  VALID_CONTEXTS = %w(
    home
    notifications
    public
    thread
    account
  ).freeze

  include Expireable

  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()')) }

  before_validation :clean_up_contexts
  after_commit :remove_cache

  def expires_in
    return @expires_in if defined?(@expires_in)
    return nil if expires_at.nil?

    [30.minutes, 1.hour, 6.hours, 12.hours, 1.day, 1.week].find { |expires_in| expires_in.from_now >= expires_at }
  end

  private

  def clean_up_contexts
    self.context = Array(context).map(&:strip).map(&:presence).compact
  end

  def remove_cache
    Rails.cache.delete("filters:#{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