forked from discourse/discourse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpromotion.rb
167 lines (137 loc) · 5.5 KB
/
promotion.rb
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
# frozen_string_literal: true
#
# Check whether a user is ready for a new trust level.
#
class Promotion
def initialize(user)
@user = user
end
# Review a user for a promotion. Delegates work to a review_#{trust_level} method.
# Returns true if the user was promoted, false otherwise.
def review
# nil users are never promoted
return false if @user.blank? || [email protected]_locked_trust_level.nil?
# Promotion beyond basic requires some expensive queries, so don't do that here.
return false if @user.trust_level >= TrustLevel[2]
review_method = :"review_tl#{@user.trust_level}"
return public_send(review_method) if respond_to?(review_method)
false
end
def review_tl0
if Promotion.tl1_met?(@user) && change_trust_level!(TrustLevel[1])
if Badge.exists?(id: Badge::BasicUser, enabled: true) &&
[email protected]?(id: Badge::BasicUser)
@user.enqueue_member_welcome_message
end
return true
end
false
end
def review_tl1
if Promotion.tl2_met?(@user) && change_trust_level!(TrustLevel[2])
@user.enqueue_tl2_promotion_message
return true
end
false
end
def review_tl2
Promotion.tl3_met?(@user) && change_trust_level!(TrustLevel[3])
end
def change_trust_level!(level, opts = {})
raise "Invalid trust level #{level}" unless TrustLevel.valid?(level)
old_level = @user.trust_level
new_level = level
if new_level < old_level && @user.manual_locked_trust_level.nil?
next_up = new_level + 1
key = "tl#{next_up}_met?"
if self.class.respond_to?(key) && self.class.public_send(key, @user)
raise Discourse::InvalidAccess.new,
I18n.t(
"trust_levels.change_failed_explanation",
user_name: @user.name,
new_trust_level: new_level,
current_trust_level: old_level,
)
end
end
admin = opts && opts[:log_action_for]
@user.trust_level = new_level
@user.user_profile.bio_raw_will_change! # So it can get re-cooked based on the new trust level
@user.transaction do
if admin
StaffActionLogger.new(admin).log_trust_level_change(@user, old_level, new_level)
else
UserHistory.create!(
action: UserHistory.actions[:auto_trust_level_change],
target_user_id: @user.id,
previous_value: old_level,
new_value: new_level,
)
end
@user.skip_email_validation = true
@user.save!
@user.user_profile.recook_bio
@user.user_profile.save!
DiscourseEvent.trigger(
:user_promoted,
user_id: @user.id,
new_trust_level: new_level,
old_trust_level: old_level,
)
Group.user_trust_level_change!(@user.id, @user.trust_level)
BadgeGranter.queue_badge_grant(Badge::Trigger::TrustLevelChange, user: @user)
end
true
end
def self.tl2_met?(user)
stat = user.user_stat
return false if stat.topics_entered < SiteSetting.tl2_requires_topics_entered
return false if stat.posts_read_count < SiteSetting.tl2_requires_read_posts
return false if (stat.time_read / 60) < SiteSetting.tl2_requires_time_spent_mins
return false if ((Time.now - user.created_at) / 60) < SiteSetting.tl2_requires_time_spent_mins
return false if stat.days_visited < SiteSetting.tl2_requires_days_visited
return false if stat.likes_received < SiteSetting.tl2_requires_likes_received
return false if stat.likes_given < SiteSetting.tl2_requires_likes_given
return false if stat.calc_topic_reply_count! < SiteSetting.tl2_requires_topic_reply_count
true
end
def self.tl1_met?(user)
stat = user.user_stat
return false if stat.topics_entered < SiteSetting.tl1_requires_topics_entered
return false if stat.posts_read_count < SiteSetting.tl1_requires_read_posts
return false if (stat.time_read / 60) < SiteSetting.tl1_requires_time_spent_mins
return false if ((Time.now - user.created_at) / 60) < SiteSetting.tl1_requires_time_spent_mins
true
end
def self.tl3_met?(user)
TrustLevel3Requirements.new(user).requirements_met?
end
def self.tl3_lost?(user)
TrustLevel3Requirements.new(user).requirements_lost?
end
# Figure out what a user's trust level should be from scratch
def self.recalculate(user, performed_by = nil, use_previous_trust_level: false)
granted_trust_level =
TrustLevel.calculate(user, use_previous_trust_level: use_previous_trust_level) ||
TrustLevel[0]
granted_trust_level = user.trust_level if granted_trust_level < user.trust_level &&
!can_downgrade_trust_level?(user)
# TrustLevel.calculate always returns a value, however we added extra protection just
# in case this changes
user.update_column(:trust_level, TrustLevel[granted_trust_level])
return if user.manual_locked_trust_level.present?
promotion = Promotion.new(user)
promotion.review_tl0 if granted_trust_level < TrustLevel[1]
promotion.review_tl1 if granted_trust_level < TrustLevel[2]
promotion.review_tl2 if granted_trust_level < TrustLevel[3]
if user.trust_level == TrustLevel[3] && Promotion.tl3_lost?(user)
user.change_trust_level!(TrustLevel[2], log_action_for: performed_by || Discourse.system_user)
end
end
def self.can_downgrade_trust_level?(user)
return false if user.trust_level == TrustLevel[1] && tl1_met?(user)
return false if user.trust_level == TrustLevel[2] && tl2_met?(user)
return false if user.trust_level == TrustLevel[3] && tl3_met?(user)
true
end
end