2019-05-02 17:17:27 -05:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2013-02-05 13:16:51 -06:00
|
|
|
#
|
|
|
|
# Check whether a user is ready for a new trust level.
|
|
|
|
#
|
|
|
|
class Promotion
|
|
|
|
def initialize(user)
|
2013-02-25 10:42:20 -06:00
|
|
|
@user = user
|
2013-02-05 13:16:51 -06:00
|
|
|
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
|
2024-10-16 10:26:10 -05:00
|
|
|
override = DiscoursePluginRegistry.apply_modifier(:review_trust_level, false, @user)
|
|
|
|
return override if override
|
|
|
|
|
2013-02-05 13:16:51 -06:00
|
|
|
# nil users are never promoted
|
2017-11-23 14:55:44 -06:00
|
|
|
return false if @user.blank? || !@user.manual_locked_trust_level.nil?
|
2013-02-05 13:16:51 -06:00
|
|
|
|
2014-06-27 11:26:03 -05:00
|
|
|
# Promotion beyond basic requires some expensive queries, so don't do that here.
|
2014-09-05 00:20:39 -05:00
|
|
|
return false if @user.trust_level >= TrustLevel[2]
|
2014-06-27 11:26:03 -05:00
|
|
|
|
2014-09-05 00:20:39 -05:00
|
|
|
review_method = :"review_tl#{@user.trust_level}"
|
2019-05-06 21:22:37 -05:00
|
|
|
return public_send(review_method) if respond_to?(review_method)
|
2013-02-05 13:16:51 -06:00
|
|
|
|
|
|
|
false
|
|
|
|
end
|
|
|
|
|
2014-09-05 00:20:39 -05:00
|
|
|
def review_tl0
|
2018-06-22 11:51:07 -05:00
|
|
|
if Promotion.tl1_met?(@user) && change_trust_level!(TrustLevel[1])
|
2021-08-10 17:39:25 -05:00
|
|
|
if Badge.exists?(id: Badge::BasicUser, enabled: true) &&
|
|
|
|
!@user.badges.exists?(id: Badge::BasicUser)
|
|
|
|
@user.enqueue_member_welcome_message
|
|
|
|
end
|
2018-06-22 11:51:07 -05:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
false
|
2014-06-16 19:46:30 -05:00
|
|
|
end
|
|
|
|
|
2014-09-05 00:20:39 -05:00
|
|
|
def review_tl1
|
2020-09-21 19:17:52 -05:00
|
|
|
if Promotion.tl2_met?(@user) && change_trust_level!(TrustLevel[2])
|
|
|
|
@user.enqueue_tl2_promotion_message
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
false
|
2014-06-16 19:46:30 -05:00
|
|
|
end
|
|
|
|
|
2014-09-05 00:20:39 -05:00
|
|
|
def review_tl2
|
|
|
|
Promotion.tl3_met?(@user) && change_trust_level!(TrustLevel[3])
|
2014-06-27 11:26:03 -05:00
|
|
|
end
|
|
|
|
|
2014-06-16 19:46:30 -05:00
|
|
|
def change_trust_level!(level, opts = {})
|
2014-09-05 00:20:39 -05:00
|
|
|
raise "Invalid trust level #{level}" unless TrustLevel.valid?(level)
|
2014-06-16 19:46:30 -05:00
|
|
|
|
|
|
|
old_level = @user.trust_level
|
2014-09-05 00:20:39 -05:00
|
|
|
new_level = level
|
2014-06-16 19:46:30 -05:00
|
|
|
|
2017-11-23 14:55:44 -06:00
|
|
|
if new_level < old_level && @user.manual_locked_trust_level.nil?
|
2014-09-05 00:20:39 -05:00
|
|
|
next_up = new_level + 1
|
|
|
|
key = "tl#{next_up}_met?"
|
2019-05-06 20:27:05 -05:00
|
|
|
if self.class.respond_to?(key) && self.class.public_send(key, @user)
|
2014-06-16 19:46:30 -05:00
|
|
|
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
|
2013-02-05 13:16:51 -06:00
|
|
|
|
2014-06-16 19:46:30 -05:00
|
|
|
admin = opts && opts[:log_action_for]
|
|
|
|
|
|
|
|
@user.trust_level = new_level
|
2014-06-16 19:58:21 -05:00
|
|
|
@user.user_profile.bio_raw_will_change! # So it can get re-cooked based on the new trust level
|
2014-06-16 19:46:30 -05:00
|
|
|
|
|
|
|
@user.transaction do
|
|
|
|
if admin
|
|
|
|
StaffActionLogger.new(admin).log_trust_level_change(@user, old_level, new_level)
|
2014-07-08 16:39:36 -05:00
|
|
|
else
|
|
|
|
UserHistory.create!(
|
|
|
|
action: UserHistory.actions[:auto_trust_level_change],
|
|
|
|
target_user_id: @user.id,
|
|
|
|
previous_value: old_level,
|
|
|
|
new_value: new_level,
|
|
|
|
)
|
2014-06-16 19:46:30 -05:00
|
|
|
end
|
2023-03-29 22:52:10 -05:00
|
|
|
@user.skip_email_validation = true
|
2014-06-16 19:46:30 -05:00
|
|
|
@user.save!
|
|
|
|
@user.user_profile.recook_bio
|
|
|
|
@user.user_profile.save!
|
2019-11-13 15:31:49 -06:00
|
|
|
DiscourseEvent.trigger(
|
|
|
|
:user_promoted,
|
|
|
|
user_id: @user.id,
|
|
|
|
new_trust_level: new_level,
|
|
|
|
old_trust_level: old_level,
|
|
|
|
)
|
2014-06-16 19:46:30 -05:00
|
|
|
Group.user_trust_level_change!(@user.id, @user.trust_level)
|
2014-07-22 20:42:24 -05:00
|
|
|
BadgeGranter.queue_badge_grant(Badge::Trigger::TrustLevelChange, user: @user)
|
2014-06-16 19:46:30 -05:00
|
|
|
end
|
2013-02-25 10:42:20 -06:00
|
|
|
|
2013-02-05 13:16:51 -06:00
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2014-09-05 00:20:39 -05:00
|
|
|
def self.tl2_met?(user)
|
2014-06-16 19:46:30 -05:00
|
|
|
stat = user.user_stat
|
2014-09-04 15:16:46 -05:00
|
|
|
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
|
2015-04-14 11:05:09 -05:00
|
|
|
return false if ((Time.now - user.created_at) / 60) < SiteSetting.tl2_requires_time_spent_mins
|
2014-09-04 15:16:46 -05:00
|
|
|
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
|
2020-08-12 09:28:34 -05:00
|
|
|
return false if stat.calc_topic_reply_count! < SiteSetting.tl2_requires_topic_reply_count
|
2013-04-04 23:29:46 -05:00
|
|
|
|
2014-06-16 19:46:30 -05:00
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2014-09-05 00:20:39 -05:00
|
|
|
def self.tl1_met?(user)
|
2014-06-16 19:46:30 -05:00
|
|
|
stat = user.user_stat
|
2014-09-04 15:16:46 -05:00
|
|
|
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
|
2015-04-14 11:05:09 -05:00
|
|
|
return false if ((Time.now - user.created_at) / 60) < SiteSetting.tl1_requires_time_spent_mins
|
|
|
|
|
2019-11-14 14:10:51 -06:00
|
|
|
true
|
2013-04-04 23:29:46 -05:00
|
|
|
end
|
|
|
|
|
2014-09-05 00:20:39 -05:00
|
|
|
def self.tl3_met?(user)
|
|
|
|
TrustLevel3Requirements.new(user).requirements_met?
|
2014-06-27 11:26:03 -05:00
|
|
|
end
|
|
|
|
|
2014-09-05 00:20:39 -05:00
|
|
|
def self.tl3_lost?(user)
|
|
|
|
TrustLevel3Requirements.new(user).requirements_lost?
|
2014-07-28 01:42:38 -05:00
|
|
|
end
|
|
|
|
|
2017-11-23 14:55:44 -06:00
|
|
|
# Figure out what a user's trust level should be from scratch
|
2022-08-29 05:00:48 -05:00
|
|
|
def self.recalculate(user, performed_by = nil, use_previous_trust_level: false)
|
|
|
|
granted_trust_level =
|
2023-02-28 22:35:21 -06:00
|
|
|
TrustLevel.calculate(user, use_previous_trust_level: use_previous_trust_level) ||
|
|
|
|
TrustLevel[0]
|
2017-11-23 14:55:44 -06:00
|
|
|
|
2024-03-03 16:30:30 -06:00
|
|
|
granted_trust_level = user.trust_level if granted_trust_level < user.trust_level &&
|
|
|
|
!can_downgrade_trust_level?(user)
|
|
|
|
|
2023-02-28 22:35:21 -06:00
|
|
|
# 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])
|
2017-11-23 14:55:44 -06:00
|
|
|
|
2023-02-28 22:35:21 -06:00
|
|
|
return if user.manual_locked_trust_level.present?
|
|
|
|
|
|
|
|
promotion = Promotion.new(user)
|
|
|
|
|
2024-10-16 10:26:10 -05:00
|
|
|
override =
|
|
|
|
DiscoursePluginRegistry.apply_modifier(:recalculate_trust_level, false, user, promotion)
|
|
|
|
return override if override
|
|
|
|
|
2023-02-28 22:35:21 -06:00
|
|
|
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)
|
2017-11-23 14:55:44 -06:00
|
|
|
end
|
|
|
|
end
|
2024-03-03 16:30:30 -06:00
|
|
|
|
|
|
|
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
|
2013-02-05 13:16:51 -06:00
|
|
|
end
|