about summary refs log tree commit diff
path: root/app/lib/command_tag/command/status_tools.rb
blob: 1cdb90e4ace676b1ac16f31b7702c1d09362a0d6 (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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# frozen_string_literal: true
module CommandTag::Command::StatusTools
  def handle_article_before_save(args)
    return unless author_of_status? && args.present?

    case args.shift.downcase
    when 'title', 'name', 't'
      status.title = args.join(' ')
    when 'summary', 'abstract', 'cw', 'cn', 's', 'a'
      @status.title = @status.spoiler_text if @status.title.blank?
      @status.spoiler_text = args.join(' ')
    end
  end

  def handle_title_before_save(args)
    args.unshift('title')
    handle_article_before_save(args)
  end

  def handle_summary_before_save(args)
    args.unshift('summary')
    handle_article_before_save(args)
  end

  alias handle_abstract_before_save handle_summary_before_save

  def handle_visibility_before_save(args)
    return unless author_of_status? && args[0].present?

    args[0] = read_visibility_from(args[0])
    return if args[0].blank?

    if args[1].blank?
      @status.visibility = args[0].to_sym
    elsif args[0] == @status.visibility.to_s
      domains = args[1..-1].map { |domain| normalize_domain(domain) unless domain == '*' }.uniq.compact
      @status.domain_permissions.where(domain: domains).destroy_all if domains.present?
    elsif args[0] == 'cc'
      expect_list = false
      args[1..-1].uniq.each do |target|
        if expect_list
          expect_list = false
          address_to_list(target)
        elsif %w(list list:).include?(target.downcase)
          expect_list = true
        else
          mention(resolve_mention(target))
        end
      end
    else
      args[1..-1].flat_map(&:split).uniq.each do |domain|
        domain = normalize_domain(domain) unless domain == '*'
        @status.domain_permissions.create_or_update(domain: domain, visibility: args[0]) if domain.present?
      end
    end
  end

  alias handle_v_before_save                      handle_visibility_before_save
  alias handle_p_before_save                      handle_visibility_before_save
  alias handle_privacy_before_save                handle_visibility_before_save

  def handle_notify_before_save(args)
    return if args[0].blank?

    @status.notify = read_boolean_from(args[0])
  end

  alias handle_notice_before_save handle_notify_before_save

  def handle_tags_before_save(args)
    return if args.blank?

    cmd = args.shift.downcase
    args.select! { |tag| tag =~ /\A(#{Tag::HASHTAG_NAME_RE})\z/i }

    case cmd
    when 'add', 'a', '+'
      ProcessHashtagsService.new.call(@status, args)
    when 'del', 'remove', 'rm', 'r', 'd', '-'
      RemoveHashtagsService.new.call(@status, args)
    end
  end

  def handle_tag_before_save(args)
    args.unshift('add')
    handle_tags_before_save(args)
  end

  def handle_untag_before_save(args)
    args.unshift('del')
    handle_tags_before_save(args)
  end

  private

  def resolve_mention(mention_text)
    return unless (match = mention_text.match(Account::MENTION_RE))

    username, domain  = match[1].split('@')
    domain            = begin
                          if TagManager.instance.local_domain?(domain)
                            nil
                          else
                            TagManager.instance.normalize_domain(domain)
                          end
                        end

    Account.find_remote(username, domain)
  end

  def mention(target_account)
    return if target_account.blank? || target_account.mentions.where(status: @status).exists?

    target_account.mentions.create(status: @status, silent: true)
  end

  def address_to_list(list_name)
    return if list_name.blank?

    list_accounts = ListAccount.joins(:list).where(lists: { account: @account }).where('LOWER(lists.title) = ?', list_name.mb_chars.downcase).includes(:account).map(&:account)
    list_accounts.each { |target_account| mention(target_account) }
  end
end