Change Anniversary badge to be multiple grant, once per year
This commit is contained in:
parent
bb82e0a041
commit
f05f1a24d3
|
@ -0,0 +1,17 @@
|
||||||
|
require_dependency 'jobs/scheduled/grant_anniversary_badges'
|
||||||
|
|
||||||
|
module Jobs
|
||||||
|
|
||||||
|
class RetroGrantAnniversary < Jobs::Onceoff
|
||||||
|
def execute_onceoff(args)
|
||||||
|
return unless SiteSetting.enable_badges
|
||||||
|
|
||||||
|
# Fill in the years of anniversary badges we missed
|
||||||
|
(2..3).each do |year|
|
||||||
|
Jobs::GrantAnniversaryBadges.new.execute(start_date: year.years.ago)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
module Jobs
|
||||||
|
class GrantAnniversaryBadges < Jobs::Scheduled
|
||||||
|
every 1.day
|
||||||
|
|
||||||
|
def execute(args)
|
||||||
|
return unless SiteSetting.enable_badges?
|
||||||
|
|
||||||
|
start_date = args[:start_date] || 1.year.ago
|
||||||
|
end_date = start_date + 1.year
|
||||||
|
|
||||||
|
fmt_end_date = end_date.iso8601(6)
|
||||||
|
fmt_start_date = start_date.iso8601(6)
|
||||||
|
|
||||||
|
results = User.exec_sql <<~SQL
|
||||||
|
SELECT u.id AS user_id
|
||||||
|
FROM users AS u
|
||||||
|
INNER JOIN posts AS p ON p.user_id = u.id
|
||||||
|
INNER JOIN topics AS t ON p.topic_id = t.id
|
||||||
|
LEFT OUTER JOIN user_badges AS ub ON ub.user_id = u.id AND
|
||||||
|
ub.badge_id = #{Badge::Anniversary} AND
|
||||||
|
ub.granted_at BETWEEN '#{fmt_start_date}' AND '#{fmt_end_date}'
|
||||||
|
WHERE u.active AND
|
||||||
|
NOT u.blocked AND
|
||||||
|
NOT p.hidden AND
|
||||||
|
p.deleted_at IS NULL AND
|
||||||
|
t.visible AND
|
||||||
|
t.archetype <> 'private_message' AND
|
||||||
|
p.created_at BETWEEN '#{fmt_start_date}' AND '#{fmt_end_date}' AND
|
||||||
|
u.created_at <= '#{fmt_start_date}'
|
||||||
|
GROUP BY u.id
|
||||||
|
HAVING COUNT(p.id) > 0 AND COUNT(ub.id) = 0
|
||||||
|
SQL
|
||||||
|
|
||||||
|
badge = Badge.find(Badge::Anniversary)
|
||||||
|
user_ids = results.map {|r| r['user_id'].to_i }
|
||||||
|
|
||||||
|
User.where(id: user_ids).each do |user|
|
||||||
|
BadgeGranter.grant(badge, user, created_at: end_date)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -34,7 +34,7 @@ class Badge < ActiveRecord::Base
|
||||||
NiceShare = 21
|
NiceShare = 21
|
||||||
GoodShare = 22
|
GoodShare = 22
|
||||||
GreatShare = 23
|
GreatShare = 23
|
||||||
OneYearAnniversary = 24
|
Anniversary = 24
|
||||||
|
|
||||||
Promoter = 25
|
Promoter = 25
|
||||||
Campaigner = 26
|
Campaigner = 26
|
||||||
|
|
|
@ -37,6 +37,7 @@ class BadgeGranter
|
||||||
post_id: @post_id,
|
post_id: @post_id,
|
||||||
seq: seq)
|
seq: seq)
|
||||||
|
|
||||||
|
return unless SiteSetting.enable_badges
|
||||||
if @granted_by != Discourse.system_user
|
if @granted_by != Discourse.system_user
|
||||||
StaffActionLogger.new(@granted_by).log_badge_grant(user_badge)
|
StaffActionLogger.new(@granted_by).log_badge_grant(user_badge)
|
||||||
end
|
end
|
||||||
|
|
|
@ -256,15 +256,16 @@ end
|
||||||
end
|
end
|
||||||
|
|
||||||
Badge.seed do |b|
|
Badge.seed do |b|
|
||||||
b.id = Badge::OneYearAnniversary
|
b.id = Badge::Anniversary
|
||||||
b.name = "Anniversary"
|
b.name = "Anniversary"
|
||||||
b.default_icon = "fa-clock-o"
|
b.default_icon = "fa-clock-o"
|
||||||
b.badge_type_id = BadgeType::Silver
|
b.badge_type_id = BadgeType::Silver
|
||||||
b.query = BadgeQueries::OneYearAnniversary
|
|
||||||
b.default_badge_grouping_id = BadgeGrouping::Community
|
b.default_badge_grouping_id = BadgeGrouping::Community
|
||||||
|
b.query = nil
|
||||||
b.trigger = Badge::Trigger::None
|
b.trigger = Badge::Trigger::None
|
||||||
b.auto_revoke = false
|
b.auto_revoke = false
|
||||||
b.system = true
|
b.system = true
|
||||||
|
b.multiple_grant = true
|
||||||
end
|
end
|
||||||
|
|
||||||
[
|
[
|
||||||
|
|
|
@ -117,23 +117,6 @@ SQL
|
||||||
(:backfill OR u.id IN (:user_ids) )
|
(:backfill OR u.id IN (:user_ids) )
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
# member for a year + has posted at least once during that year
|
|
||||||
OneYearAnniversary = <<-SQL
|
|
||||||
SELECT u.id AS user_id, MIN(u.created_at + interval '1 year') AS granted_at
|
|
||||||
FROM users u
|
|
||||||
JOIN posts p ON p.user_id = u.id
|
|
||||||
WHERE u.id > 0
|
|
||||||
AND u.active
|
|
||||||
AND NOT u.blocked
|
|
||||||
AND u.created_at + interval '1 year' < now()
|
|
||||||
AND p.deleted_at IS NULL
|
|
||||||
AND NOT p.hidden
|
|
||||||
AND p.created_at + interval '1 year' > now()
|
|
||||||
AND (:backfill OR u.id IN (:user_ids))
|
|
||||||
GROUP BY u.id
|
|
||||||
HAVING COUNT(p.id) > 0
|
|
||||||
SQL
|
|
||||||
|
|
||||||
FirstMention = <<-SQL
|
FirstMention = <<-SQL
|
||||||
SELECT acting_user_id AS user_id, min(target_post_id) AS post_id, min(p.created_at) AS granted_at
|
SELECT acting_user_id AS user_id, min(target_post_id) AS post_id, min(p.created_at) AS granted_at
|
||||||
FROM user_actions
|
FROM user_actions
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
require_dependency 'jobs/scheduled/grant_anniversary_badges'
|
||||||
|
|
||||||
|
describe Jobs::GrantAnniversaryBadges do
|
||||||
|
|
||||||
|
let(:granter) { described_class.new }
|
||||||
|
|
||||||
|
it "doesn't award to a user who is less than a year old" do
|
||||||
|
user = Fabricate(:user, created_at: 1.month.ago)
|
||||||
|
Fabricate(:post, user: user, created_at: 1.week.ago)
|
||||||
|
granter.execute({})
|
||||||
|
|
||||||
|
badge = user.user_badges.where(badge_id: Badge::Anniversary)
|
||||||
|
expect(badge).to be_blank
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't award to an inactive user" do
|
||||||
|
user = Fabricate(:user, created_at: 400.days.ago, active: false)
|
||||||
|
Fabricate(:post, user: user, created_at: 1.week.ago)
|
||||||
|
granter.execute({})
|
||||||
|
|
||||||
|
badge = user.user_badges.where(badge_id: Badge::Anniversary)
|
||||||
|
expect(badge).to be_blank
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't award to a blocked user" do
|
||||||
|
user = Fabricate(:user, created_at: 400.days.ago, blocked: true)
|
||||||
|
Fabricate(:post, user: user, created_at: 1.week.ago)
|
||||||
|
granter.execute({})
|
||||||
|
|
||||||
|
badge = user.user_badges.where(badge_id: Badge::Anniversary)
|
||||||
|
expect(badge).to be_blank
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't award when a post is deleted" do
|
||||||
|
user = Fabricate(:user, created_at: 400.days.ago)
|
||||||
|
Fabricate(:post, user: user, created_at: 1.week.ago, deleted_at: 1.day.ago)
|
||||||
|
granter.execute({})
|
||||||
|
|
||||||
|
badge = user.user_badges.where(badge_id: Badge::Anniversary)
|
||||||
|
expect(badge).to be_blank
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't award when a post is hidden" do
|
||||||
|
user = Fabricate(:user, created_at: 400.days.ago)
|
||||||
|
Fabricate(:post, user: user, created_at: 1.week.ago, hidden: true)
|
||||||
|
granter.execute({})
|
||||||
|
|
||||||
|
badge = user.user_badges.where(badge_id: Badge::Anniversary)
|
||||||
|
expect(badge).to be_blank
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't award to PMs" do
|
||||||
|
user = Fabricate(:user, created_at: 400.days.ago)
|
||||||
|
Fabricate(:private_message_post, user: user, created_at: 1.week.ago)
|
||||||
|
granter.execute({})
|
||||||
|
|
||||||
|
badge = user.user_badges.where(badge_id: Badge::Anniversary)
|
||||||
|
expect(badge).to be_blank
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't award to a user without a post" do
|
||||||
|
user = Fabricate(:user, created_at: 1.month.ago)
|
||||||
|
granter.execute({})
|
||||||
|
|
||||||
|
badge = user.user_badges.where(badge_id: Badge::Anniversary)
|
||||||
|
expect(badge).to be_blank
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't award when badges are disabled" do
|
||||||
|
SiteSetting.enable_badges = false
|
||||||
|
|
||||||
|
user = Fabricate(:user, created_at: 400.days.ago)
|
||||||
|
Fabricate(:post, user: user, created_at: 1.week.ago)
|
||||||
|
|
||||||
|
granter.execute({})
|
||||||
|
badge = user.user_badges.where(badge_id: Badge::Anniversary)
|
||||||
|
expect(badge.count).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "awards the badge to a user with a post active for a year" do
|
||||||
|
user = Fabricate(:user, created_at: 400.days.ago)
|
||||||
|
Fabricate(:post, user: user, created_at: 1.week.ago)
|
||||||
|
|
||||||
|
granter.execute({})
|
||||||
|
badge = user.user_badges.where(badge_id: Badge::Anniversary)
|
||||||
|
expect(badge.count).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "repeated grants" do
|
||||||
|
it "won't award twice in the same year" do
|
||||||
|
user = Fabricate(:user, created_at: 400.days.ago)
|
||||||
|
Fabricate(:post, user: user, created_at: 1.week.ago)
|
||||||
|
|
||||||
|
granter.execute({})
|
||||||
|
granter.execute({})
|
||||||
|
badge = user.user_badges.where(badge_id: Badge::Anniversary)
|
||||||
|
expect(badge.count).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "will award again if a year has passed" do
|
||||||
|
user = Fabricate(:user, created_at: 800.days.ago)
|
||||||
|
Fabricate(:post, user: user, created_at: 450.days.ago)
|
||||||
|
|
||||||
|
Timecop.freeze(400.days.ago) do
|
||||||
|
granter.execute({})
|
||||||
|
end
|
||||||
|
badge = user.user_badges.where(badge_id: Badge::Anniversary)
|
||||||
|
expect(badge.count).to eq(1)
|
||||||
|
|
||||||
|
Fabricate(:post, user: user, created_at: 50.days.ago)
|
||||||
|
granter.execute({})
|
||||||
|
badge = user.user_badges.where(badge_id: Badge::Anniversary)
|
||||||
|
expect(badge.count).to eq(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports date ranges" do
|
||||||
|
user = Fabricate(:user, created_at: 3.years.ago)
|
||||||
|
Fabricate(:post, user: user, created_at: 750.days.ago)
|
||||||
|
|
||||||
|
granter.execute(start_date: 800.days.ago)
|
||||||
|
badge = user.user_badges.where(badge_id: Badge::Anniversary)
|
||||||
|
expect(badge.count).to eq(1)
|
||||||
|
|
||||||
|
Fabricate(:post, user: user, created_at: 50.days.ago)
|
||||||
|
granter.execute(start_date: 800.days.ago)
|
||||||
|
badge = user.user_badges.where(badge_id: Badge::Anniversary)
|
||||||
|
expect(badge.count).to eq(1)
|
||||||
|
|
||||||
|
granter.execute(start_date: 60.days.ago)
|
||||||
|
badge = user.user_badges.where(badge_id: Badge::Anniversary)
|
||||||
|
expect(badge.count).to eq(2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in New Issue