Class: TrustLevel3Requirements

Inherits:
Object
  • Object
show all
Includes:
ActiveModel::Serialization
Defined in:
app/models/trust_level3_requirements.rb

Overview

This class performs calculations to determine if a user qualifies for the Leader (3) trust level.

Defined Under Namespace

Classes: PenaltyCounts

Constant Summary collapse

LOW_WATER_MARK =
0.9
FORGIVENESS_PERIOD =
6.months
CACHE_DURATION =
1.day.seconds - 60
NUM_TOPICS_KEY =
"tl3_num_topics"
NUM_POSTS_KEY =
"tl3_num_posts"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(user) ⇒ TrustLevel3Requirements

Returns a new instance of TrustLevel3Requirements.



29
30
31
# File 'app/models/trust_level3_requirements.rb', line 29

def initialize(user)
  @user = user
end

Class Method Details

.clear_cacheObject



261
262
263
264
# File 'app/models/trust_level3_requirements.rb', line 261

def self.clear_cache
  Discourse.redis.del NUM_TOPICS_KEY
  Discourse.redis.del NUM_POSTS_KEY
end

.num_posts_in_time_periodObject



280
281
282
283
284
285
286
287
# File 'app/models/trust_level3_requirements.rb', line 280

def self.num_posts_in_time_period
  Discourse.redis.get(NUM_POSTS_KEY) ||
    begin
      count = Post.public_posts.visible.created_since(SiteSetting.tl3_time_period.days.ago).count
      Discourse.redis.setex NUM_POSTS_KEY, CACHE_DURATION, count
      count
    end
end

.num_topics_in_time_periodObject



270
271
272
273
274
275
276
277
278
# File 'app/models/trust_level3_requirements.rb', line 270

def self.num_topics_in_time_period
  Discourse.redis.get(NUM_TOPICS_KEY) ||
    begin
      count =
        Topic.listable_topics.visible.created_since(SiteSetting.tl3_time_period.days.ago).count
      Discourse.redis.setex NUM_TOPICS_KEY, CACHE_DURATION, count
      count
    end
end

Instance Method Details

#days_visitedObject



77
78
79
# File 'app/models/trust_level3_requirements.rb', line 77

def days_visited
  @user.user_visits.where("visited_at > ? and posts_read > 0", time_period.days.ago).count
end

#flagged_post_idsObject



289
290
291
292
293
294
295
296
297
298
299
# File 'app/models/trust_level3_requirements.rb', line 289

def flagged_post_ids
  @_flagged_post_ids ||=
    @user
      .posts
      .with_deleted
      .where(
        "created_at > ? AND (spam_count > 0 OR inappropriate_count > 0)",
        time_period.days.ago,
      )
      .pluck(:id)
end

#max_flagged_by_usersObject



208
209
210
# File 'app/models/trust_level3_requirements.rb', line 208

def max_flagged_by_users
  SiteSetting.tl3_requires_max_flagged
end

#max_flagged_postsObject



192
193
194
# File 'app/models/trust_level3_requirements.rb', line 192

def max_flagged_posts
  SiteSetting.tl3_requires_max_flagged
end

#min_days_visitedObject



117
118
119
# File 'app/models/trust_level3_requirements.rb', line 117

def min_days_visited
  SiteSetting.tl3_requires_days_visited
end

#min_likes_givenObject



221
222
223
# File 'app/models/trust_level3_requirements.rb', line 221

def min_likes_given
  SiteSetting.tl3_requires_likes_given
end

#min_likes_receivedObject



237
238
239
# File 'app/models/trust_level3_requirements.rb', line 237

def min_likes_received
  SiteSetting.tl3_requires_likes_received
end

#min_likes_received_daysObject



246
247
248
249
250
# File 'app/models/trust_level3_requirements.rb', line 246

def min_likes_received_days
  # Since min_likes_received / 3 can be greater than the number of days in time_period,
  # cap this result to be less than time_period.
  [(min_likes_received.to_f / 3.0).ceil, (0.75 * time_period.to_f).ceil].min
end

#min_likes_received_usersObject



257
258
259
# File 'app/models/trust_level3_requirements.rb', line 257

def min_likes_received_users
  (min_likes_received.to_f / 4.0).ceil
end

#min_posts_readObject



155
156
157
158
159
160
161
162
163
# File 'app/models/trust_level3_requirements.rb', line 155

def min_posts_read
  [
    (
      TrustLevel3Requirements.num_posts_in_time_period.to_i *
        (SiteSetting.tl3_requires_posts_read.to_f / 100.0)
    ).round,
    SiteSetting.tl3_requires_posts_read_cap,
  ].min
end

#min_posts_read_all_timeObject



177
178
179
# File 'app/models/trust_level3_requirements.rb', line 177

def min_posts_read_all_time
  SiteSetting.tl3_requires_posts_read_all_time
end

#min_topics_replied_toObject



125
126
127
# File 'app/models/trust_level3_requirements.rb', line 125

def min_topics_replied_to
  SiteSetting.tl3_requires_topics_replied_to
end

#min_topics_viewedObject



141
142
143
144
145
146
147
148
149
# File 'app/models/trust_level3_requirements.rb', line 141

def min_topics_viewed
  [
    (
      TrustLevel3Requirements.num_topics_in_time_period.to_i *
        (SiteSetting.tl3_requires_topics_viewed.to_f / 100.0)
    ).round,
    SiteSetting.tl3_requires_topics_viewed_cap,
  ].min
end

#min_topics_viewed_all_timeObject



169
170
171
# File 'app/models/trust_level3_requirements.rb', line 169

def min_topics_viewed_all_time
  SiteSetting.tl3_requires_topics_viewed_all_time
end

#num_flagged_by_usersObject



196
197
198
199
200
201
202
203
204
205
206
# File 'app/models/trust_level3_requirements.rb', line 196

def num_flagged_by_users
  @_num_flagged_by_users ||=
    PostAction
      .with_deleted
      .where(post_id: flagged_post_ids)
      .where.not(user_id: @user.id)
      .where.not(agreed_at: nil)
      .pluck(:user_id)
      .uniq
      .count
end

#num_flagged_postsObject



181
182
183
184
185
186
187
188
189
190
# File 'app/models/trust_level3_requirements.rb', line 181

def num_flagged_posts
  PostAction
    .with_deleted
    .where(post_id: flagged_post_ids)
    .where.not(user_id: @user.id)
    .where.not(agreed_at: nil)
    .pluck(:post_id)
    .uniq
    .count
end

#num_likes_givenObject



212
213
214
215
216
217
218
219
# File 'app/models/trust_level3_requirements.rb', line 212

def num_likes_given
  UserAction
    .where(user_id: @user.id, action_type: UserAction::LIKE)
    .where("user_actions.created_at > ?", time_period.days.ago)
    .joins(:target_topic)
    .where("topics.archetype <> ?", Archetype.private_message)
    .count
end

#num_likes_receivedObject



233
234
235
# File 'app/models/trust_level3_requirements.rb', line 233

def num_likes_received
  num_likes_received_query.count
end

#num_likes_received_daysObject



241
242
243
244
# File 'app/models/trust_level3_requirements.rb', line 241

def num_likes_received_days
  # don't do a COUNT(DISTINCT date(created_at)) here!
  num_likes_received_query.pluck("date(user_actions.created_at)").uniq.size
end

#num_likes_received_queryObject



225
226
227
228
229
230
231
# File 'app/models/trust_level3_requirements.rb', line 225

def num_likes_received_query
  UserAction
    .where(user_id: @user.id, action_type: UserAction::WAS_LIKED)
    .where("user_actions.created_at > ?", time_period.days.ago)
    .joins(:target_topic)
    .where("topics.archetype <> ?", Archetype.private_message)
end

#num_likes_received_usersObject



252
253
254
255
# File 'app/models/trust_level3_requirements.rb', line 252

def num_likes_received_users
  # don't do a COUNT(DISTINCT acting_user_id) here!
  num_likes_received_query.pluck(:acting_user_id).uniq.size
end

#num_topics_replied_toObject



121
122
123
# File 'app/models/trust_level3_requirements.rb', line 121

def num_topics_replied_to
  @user.user_stat.calc_topic_reply_count!(time_period.days.ago)
end

#on_grace_periodObject



73
74
75
# File 'app/models/trust_level3_requirements.rb', line 73

def on_grace_period
  @user.on_tl3_grace_period?
end

#penalty_countsObject



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
# File 'app/models/trust_level3_requirements.rb', line 81

def penalty_counts
  args = {
    user_id: @user.id,
    system_user_id: Discourse.system_user.id,
    silence_user: UserHistory.actions[:silence_user],
    unsilence_user: UserHistory.actions[:unsilence_user],
    suspend_user: UserHistory.actions[:suspend_user],
    unsuspend_user: UserHistory.actions[:unsuspend_user],
    since: FORGIVENESS_PERIOD.ago,
  }

  sql = <<~SQL
    SELECT
    SUM(
        CASE
          WHEN action = :silence_user THEN 1
          WHEN action = :unsilence_user AND acting_user_id != :system_user_id THEN -1
          ELSE 0
        END
      ) AS silence_count,
      SUM(
        CASE
          WHEN action = :suspend_user THEN 1
          WHEN action = :unsuspend_user AND acting_user_id != :system_user_id THEN -1
          ELSE 0
        END
      ) AS suspend_count
    FROM user_histories AS uh
    WHERE uh.target_user_id = :user_id
      AND uh.action IN (:silence_user, :suspend_user, :unsilence_user, :unsuspend_user)
      AND uh.created_at > :since
  SQL

  PenaltyCounts.new(@user, DB.query_hash(sql, args).first)
end

#posts_readObject



151
152
153
# File 'app/models/trust_level3_requirements.rb', line 151

def posts_read
  @user.user_visits.where("visited_at > ?", time_period.days.ago).pluck(:posts_read).sum
end

#posts_read_all_timeObject



173
174
175
# File 'app/models/trust_level3_requirements.rb', line 173

def posts_read_all_time
  @user.user_visits.pluck(:posts_read).sum
end

#requirements_lost?Boolean

Returns:

  • (Boolean)


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'app/models/trust_level3_requirements.rb', line 47

def requirements_lost?
  return false if trust_level_locked
  return false if SiteSetting.default_trust_level > 2

  @user.suspended? || @user.silenced? || penalty_counts.total > 0 ||
    days_visited < min_days_visited * LOW_WATER_MARK ||
    num_topics_replied_to < min_topics_replied_to * LOW_WATER_MARK ||
    topics_viewed < min_topics_viewed * LOW_WATER_MARK ||
    posts_read < min_posts_read * LOW_WATER_MARK || num_flagged_posts > max_flagged_posts ||
    num_flagged_by_users > max_flagged_by_users ||
    topics_viewed_all_time < min_topics_viewed_all_time ||
    posts_read_all_time < min_posts_read_all_time ||
    num_likes_given < min_likes_given * LOW_WATER_MARK ||
    num_likes_received < min_likes_received * LOW_WATER_MARK ||
    num_likes_received_users < min_likes_received_users * LOW_WATER_MARK ||
    num_likes_received_days < min_likes_received_days * LOW_WATER_MARK
end

#requirements_met?Boolean

Returns:

  • (Boolean)


33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'app/models/trust_level3_requirements.rb', line 33

def requirements_met?
  return false if trust_level_locked

  (!@user.suspended?) && (!@user.silenced?) && penalty_counts.total == 0 &&
    days_visited >= min_days_visited && num_topics_replied_to >= min_topics_replied_to &&
    topics_viewed >= min_topics_viewed && posts_read >= min_posts_read &&
    num_flagged_posts <= max_flagged_posts && num_flagged_by_users <= max_flagged_by_users &&
    topics_viewed_all_time >= min_topics_viewed_all_time &&
    posts_read_all_time >= min_posts_read_all_time && num_likes_given >= min_likes_given &&
    num_likes_received >= min_likes_received &&
    num_likes_received_users >= min_likes_received_users &&
    num_likes_received_days >= min_likes_received_days
end

#time_periodObject



65
66
67
# File 'app/models/trust_level3_requirements.rb', line 65

def time_period
  SiteSetting.tl3_time_period
end

#topics_viewedObject



137
138
139
# File 'app/models/trust_level3_requirements.rb', line 137

def topics_viewed
  topics_viewed_query.where("viewed_at > ?", time_period.days.ago).count
end

#topics_viewed_all_timeObject



165
166
167
# File 'app/models/trust_level3_requirements.rb', line 165

def topics_viewed_all_time
  topics_viewed_query.count
end

#topics_viewed_queryObject



129
130
131
132
133
134
135
# File 'app/models/trust_level3_requirements.rb', line 129

def topics_viewed_query
  TopicViewItem
    .where(user_id: @user.id)
    .joins(:topic)
    .where("topics.archetype <> ?", Archetype.private_message)
    .select("topic_id")
end

#trust_level_lockedObject



69
70
71
# File 'app/models/trust_level3_requirements.rb', line 69

def trust_level_locked
  !@user.manual_locked_trust_level.nil?
end