Class: Jobs::GrantNewUserOfTheMonthBadges

Inherits:
Scheduled show all
Defined in:
app/jobs/scheduled/grant_new_user_of_the_month_badges.rb

Constant Summary collapse

MAX_AWARDED =
2

Instance Method Summary collapse

Methods inherited from Scheduled

#perform

Methods inherited from Base

acquire_cluster_concurrency_lock!, clear_cluster_concurrency_lock!, cluster_concurrency, cluster_concurrency_redis_key, delayed_perform, #error_context, get_cluster_concurrency, #last_db_duration, #log, #perform, #perform_immediately

Instance Method Details

#execute(args) ⇒ Object



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
# File 'app/jobs/scheduled/grant_new_user_of_the_month_badges.rb', line 9

def execute(args)
  badge = Badge.find(Badge::NewUserOfTheMonth)
  return unless SiteSetting.enable_badges? && badge.enabled?

  previous_month_beginning = 1.month.ago.beginning_of_month
  previous_month_end = 1.month.ago.end_of_month

  if UserBadge.where(
       "badge_id = ? AND granted_at BETWEEN ? AND ?",
       badge.id,
       previous_month_beginning,
       Time.zone.now,
     ).exists?
    return
  end

  scores(previous_month_beginning, previous_month_end).each do |user_id, score|
    # Don't bother awarding to users who haven't received any likes
    if score > 0.0
      user = User.find(user_id)
      if user.badges.where(id: Badge::NewUserOfTheMonth).blank?
        BadgeGranter.grant(badge, user, created_at: previous_month_end)

        SystemMessage.new(user).create(
          "new_user_of_the_month",
          month_year: I18n.l(previous_month_beginning, format: :no_day),
          url: "#{Discourse.base_url}/badges",
        )
      end
    end
  end
end

#scores(min_user_created_at, max_user_created_at) ⇒ Object



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
# File 'app/jobs/scheduled/grant_new_user_of_the_month_badges.rb', line 42

def scores(min_user_created_at, max_user_created_at)
  current_owners = UserBadge.where(badge_id: Badge::NewUserOfTheMonth).pluck(:user_id)
  current_owners = [-1] if current_owners.blank?

  # Find recent accounts and come up with a score based on how many likes they
  # received, based on how much they posted and how old the accounts of the people
  # who voted on them are.
  sql = <<~SQL
    SELECT u.id,
      SUM(CASE
          WHEN pa.id IS NOT NULL THEN
            CASE
            WHEN liked_by.id <= 0         THEN 0.0
            WHEN liked_by.admin           THEN 3.0
            WHEN liked_by.moderator       THEN 3.0
            WHEN liked_by.trust_level = 4 THEN 2.0
            WHEN liked_by.trust_level = 3 THEN 1.5
            WHEN liked_by.trust_level = 2 THEN 1.0
            WHEN liked_by.trust_level = 1 THEN 0.25
            WHEN liked_by.trust_level = 0 THEN 0.1
            ELSE 1.0
            END
          ELSE 0
          END) / (5 + COUNT(DISTINCT p.id))::float AS score
    FROM users AS u
    INNER JOIN user_stats        AS us       ON u.id = us.user_id
    LEFT OUTER JOIN posts        AS p        ON p.user_id = u.id
    LEFT OUTER JOIN post_actions AS pa       ON pa.post_id = p.id AND pa.post_action_type_id = #{PostActionType.types[:like]}
    LEFT OUTER JOIN users        AS liked_by ON liked_by.id = pa.user_id
    LEFT OUTER JOIN topics       AS t        ON t.id = p.topic_id
    WHERE u.active
      AND u.id > 0
      AND u.id NOT IN (#{current_owners.join(",")})
      AND NOT u.staged
      AND NOT u.admin
      AND NOT u.moderator
      AND u.suspended_at IS NULL
      AND u.suspended_till IS NULL
      AND u.created_at BETWEEN :min_user_created_at AND :max_user_created_at
      AND t.archetype <> '#{Archetype.private_message}'
      AND t.deleted_at IS NULL
      AND p.deleted_at IS NULL
    GROUP BY u.id
    HAVING COUNT(DISTINCT p.id) > 1
       AND COUNT(DISTINCT p.topic_id) > 1
       AND COUNT(pa.id) > 1
    ORDER BY score DESC
    LIMIT #{MAX_AWARDED}
  SQL

  Hash[
    *DB.query_single(
      sql,
      min_user_created_at: min_user_created_at,
      max_user_created_at: max_user_created_at,
    )
  ]
end