about summary refs log tree commit diff
path: root/app/policies/status_policy.rb
blob: 69d18c4bf45994584153fe8e37106e18c77dc5dd (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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# frozen_string_literal: true

class StatusPolicy < ApplicationPolicy
  def initialize(current_account, record, preloaded_relations = {})
    super(current_account, record)

    @preloaded_relations = preloaded_relations
  end

  def index?
    staff?
  end

  def show?
    return false if local_only? && (current_account.nil? || !current_account.local?)
    return false unless published? || owned?

    if requires_mention?
      owned? || mention_exists?
    elsif private?
      owned? || following_owners? || mention_exists?
    else
      current_account.nil? || !blocked_by_owners?
    end
  end

  def reblog?
    !requires_mention? && (!private? || owned?) && show? && !blocking_author?
  end

  def favourite?
    show? && !blocking_author?
  end

  def destroy?
    staff? || owned?
  end

  alias unreblog? destroy?

  def update?
    staff?
  end

  private

  def requires_mention?
    %w(direct limited).include?(visibility_for_remote_domain)
  end

  def owned?
    author.id == current_account&.id
  end

  def private?
    visibility_for_remote_domain == 'private' || !public_conversation?
  end

  def mention_exists?
    return false if current_account.nil?

    if record.mentions.loaded?
      record.mentions.any? { |mention| mention.account_id == current_account.id }
    else
      record.mentions.where(account: current_account).exists?
    end
  end

  def author_blocking_domain?
    return false if current_account.nil? || current_account.domain.nil?

    author.domain_blocking?(current_account.domain)
  end

  def parent_author_blocking_domain?
    return false if current_account.nil? || current_account.domain.nil? || parent_author.nil?

    parent_author.domain_blocking?(current_account.domain)
  end

  def conversation_author_blocking_domain?
    return false if current_account.nil? || current_account.domain.nil? || conversation_owner.nil?

    conversation_owner.domain_blocking?(current_account.domain)
  end

  def blocking_author?
    return false if current_account.nil?

    @preloaded_relations[:blocking] ? @preloaded_relations[:blocking][author.id] : current_account.blocking?(author)
  end

  def author_blocking?
    return false if current_account.nil?

    @preloaded_relations[:blocked_by] ? @preloaded_relations[:blocked_by][author.id] : author.blocking?(current_account)
  end

  def parent_author_blocking?
    return false if current_account.nil? || parent_author.nil?

    @preloaded_relations[:blocked_by] ? @preloaded_relations[:blocked_by][parent_author.id] : parent_author.blocking?(current_account)
  end

  def conversation_author_blocking?
    return public_conversation? if conversation_owner.nil?

    @preloaded_relations[:blocked_by] ? @preloaded_relations[:blocked_by][conversation_owner.id] : conversation_owner.blocking?(current_account)
  end

  def blocked_by_owners?
    return (author_blocking? || author_blocking_domain?) if conversation_owner&.id == author.id && parent_author&.id == author.id
    return true if conversation_author_blocking? || parent_author_blocking? || author_blocking?

    conversation_author_blocking_domain? || parent_author_blocking_domain? || author_blocking_domain?
  end

  def following_author?
    return false if current_account.nil?

    @preloaded_relations[:following] ? @preloaded_relations[:following][author.id] : current_account.following?(author)
  end

  def following_parent_author?
    return false if current_account.nil?
    return true if parent_author.nil?

    @preloaded_relations[:following] ? @preloaded_relations[:following][parent_author.id] : current_account.following?(parent_author)
  end

  def following_conversation_owner?
    return false if current_account.nil?
    return public_conversation? if conversation_owner.nil?

    @preloaded_relations[:following] ? @preloaded_relations[:following][conversation_owner.id] : current_account.following?(conversation_owner)
  end

  def following_owners?
    return following_author? if conversation_owner&.id == author.id && parent_author&.id == author.id

    following_conversation_owner? && following_parent_author? && following_author?
  end

  def author
    @author ||= record.account
  end

  def parent_author
    @parent_author ||= record.in_reply_to_account
  end

  def conversation_owner
    @conversation_owner ||= record.conversation&.account
  end

  def local_only?
    record.local_only?
  end

  def published?
    record.published?
  end

  def public_conversation?
    @public_conversation ||= (record.conversation&.public? || false)
  end

  def visibility_for_remote_domain
    @visibility_for_domain ||= record.visibility_for_domain(current_account&.domain)
  end
end