Wellness badge query+service refactor (#17592)

* Query +service slight refactor

* 33 week comment
This commit is contained in:
Fernando Valverde 2022-05-09 16:44:50 -06:00 committed by GitHub
parent 6d6287d93f
commit bf4d34fe9c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 69 additions and 53 deletions

View file

@ -2,8 +2,8 @@
# [
# {
# "user_id"=>11,
# "serialized_weeks_ago"=>"1,16,20",
# "serialized_comment_counts"=>"2,2,1"
# "serialized_weeks_ago"=>"0,1,16,20",
# "serialized_comment_counts"=>"2,2,1,3"
# },
# ...
# ]
@ -33,19 +33,19 @@ module Comments
SELECT user_id,
COUNT(user_id) AS number_of_comments_with_positive_reaction,
/* Get the number of weeks, since today for posts */
(trunc((extract(epoch FROM (current_timestamp- created_at))) / 604800) + 1) AS weeks_ago
trunc((extract(epoch FROM (current_timestamp- created_at))) / 604800) AS weeks_ago
FROM comments
INNER JOIN
(
SELECT DISTINCT reactable_id
FROM reactions
WHERE reactable_type = 'Comment'
AND created_at > (now() - interval '224' day)
AND created_at > (now() - interval '231' day)
EXCEPT
SELECT DISTINCT reactable_id
FROM reactions
WHERE reactable_type = 'Comment'
AND created_at > (now() - interval '224' day)
AND created_at > (now() - interval '231' day)
AND category IN ('thumbsdown', 'vomit')) AS negative_reactions
ON comments.id = negative_reactions.reactable_id
INNER JOIN
@ -53,13 +53,14 @@ module Comments
SELECT count(id) AS number_of_comments,
user_id AS comment_counts_user_id
FROM comments
WHERE created_at >= (now() - interval '7' day)
/* This interval filters week 1 (what we care about) */
WHERE created_at >= (now() - interval '14' day)
AND created_at <= (now() - interval '7' day)
GROUP BY user_id) AS comment_counts
ON comments.user_id = comment_counts_user_id
AND comment_counts.number_of_comments > 1
/* Dont select anything older than 224 days ago, or 32 weeks ago */
WHERE created_at > (now() - interval '224' day)
AND created_at < (now() - interval '3' day)
/* Dont select anything older than 231 days ago, or 33 weeks ago */
WHERE created_at > (now() - interval '231' day)
GROUP BY user_id, weeks_ago) AS user_comment_counts_by_week
GROUP BY user_id
SQL

View file

@ -13,13 +13,16 @@ module Badges
# `weeks_ago` can have values like the following:
# - [1,2,10,11,12]
# - [5]
# - [1,2,3,4,5,6,7,8]
# - [0,5]
# - [0,1,2,3,4,5,6,7,8]
# - [1,4,17]
# We only care for active streak (starting at 1) so we need to filter
# these to check how far back the (continuous) streak goes
week_streak = 0
weeks_ago.each_with_index do |week, index|
# Week 0 are comments that exist but aren't at least 1 week old yet
next if week.zero?
# Must have 2 or more non-flagged comments posted on that week
next unless comment_counts[index] > 1

View file

@ -15,38 +15,43 @@ RSpec.describe Comments::CommunityWellnessQuery, type: :query do
# don't meet the query criteria: min 2 comments in a week within last 32 weeks
before do
# User 3 - only one comment
create_comment_time_ago(user3.id, 5.days.ago, commentable: articles.sample)
create_comment_time_ago(user3.id, 8.days.ago, commentable: articles.sample)
# User 4 - has 3 comments but doesn't meet criteria bc comments are too old
create_comment_time_ago(user4.id, 226.days.ago, commentable: articles.sample)
create_comment_time_ago(user4.id, 227.days.ago, commentable: articles.sample)
create_comment_time_ago(user4.id, 227.days.ago, commentable: articles.sample)
create_comment_time_ago(user4.id, 233.days.ago, commentable: articles.sample)
create_comment_time_ago(user4.id, 237.days.ago, commentable: articles.sample)
create_comment_time_ago(user4.id, 239.days.ago, commentable: articles.sample)
end
context "when multiple users match criteria" do
before do
# User 1 - week 1
# User 1 - week 0
create_comment_time_ago(user1.id, 5.days.ago, commentable: articles.sample)
create_comment_time_ago(user1.id, 6.days.ago, commentable: articles.sample)
# User 1 - week 2
# User 1 - week 1
create_comment_time_ago(user1.id, 8.days.ago, commentable: articles.sample)
create_comment_time_ago(user1.id, 11.days.ago, commentable: articles.sample)
# User 2 - week 1
create_comment_time_ago(user2.id, 4.days.ago, commentable: articles.sample)
create_comment_time_ago(user2.id, 6.days.ago, commentable: articles.sample)
# User 1 - week 2
create_comment_time_ago(user1.id, 15.days.ago, commentable: articles.sample)
create_comment_time_ago(user1.id, 15.days.ago, commentable: articles.sample)
# User 2 - week 0
create_comment_time_ago(user2.id, 1.day.ago, commentable: articles.sample)
# User 2 - week 1
create_comment_time_ago(user2.id, 9.days.ago, commentable: articles.sample)
create_comment_time_ago(user2.id, 13.days.ago, commentable: articles.sample)
# User 1 - week 3
create_comment_time_ago(user2.id, 17.days.ago, commentable: articles.sample)
# User 2 - week 2
create_comment_time_ago(user2.id, 17.days.ago, commentable: articles.sample)
create_comment_time_ago(user2.id, 18.days.ago, commentable: articles.sample)
create_comment_time_ago(user2.id, 18.days.ago, commentable: articles.sample)
# User 2 - week 3
create_comment_time_ago(user2.id, 22.days.ago, commentable: articles.sample)
create_comment_time_ago(user2.id, 23.days.ago, commentable: articles.sample)
create_comment_time_ago(user2.id, 23.days.ago, commentable: articles.sample)
# User 5 - has 2 comments in the first week but too early to award because
# comments must be 3 days old or more to give mods time to flag before award
create_comment_time_ago(user5.id, 2.days.ago, commentable: articles.sample)
create_comment_time_ago(user5.id, 6.days.ago, commentable: articles.sample)
# User 5 - week 1
create_comment_time_ago(user5.id, 8.days.ago, commentable: articles.sample)
create_comment_time_ago(user5.id, 10.days.ago, commentable: articles.sample)
end
it "returns the correct data structure (array of hashes w/ correct keys)" do
@ -69,40 +74,46 @@ RSpec.describe Comments::CommunityWellnessQuery, type: :query do
expect(result_user_ids).to contain_exactly(user1.id, user2.id, user5.id)
index1 = result.index { |hash| hash["user_id"] == user1.id }
expect(result[index1]["serialized_weeks_ago"]).to eq("1,2")
expect(result[index1]["serialized_comment_counts"]).to eq("2,2")
expect(result[index1]["serialized_weeks_ago"]).to eq("0,1,2")
expect(result[index1]["serialized_comment_counts"]).to eq("2,2,2")
index2 = result.index { |hash| hash["user_id"] == user2.id }
expect(result[index2]["serialized_weeks_ago"]).to eq("1,2,3")
expect(result[index2]["serialized_comment_counts"]).to eq("2,2,3")
expect(result[index2]["serialized_weeks_ago"]).to eq("0,1,2,3")
expect(result[index2]["serialized_comment_counts"]).to eq("1,2,3,3")
# user5 will still appear in the query because it has 2 comments in the
# week but the count will reflect only those that are 3+ days old
# user5 will still appear in the query despite not having any comments in
# week 0, because we start counting at week 1 to award the badge
index5 = result.index { |hash| hash["user_id"] == user5.id }
expect(result[index5]["serialized_weeks_ago"]).to eq("1")
expect(result[index5]["serialized_comment_counts"]).to eq("1")
expect(result[index5]["serialized_comment_counts"]).to eq("2")
end
end
context "when users match criteria but mod reaction reduces their comment counts" do
before do
# User 1 - week 1
create_comment_time_ago(user1.id, 5.days.ago, commentable: articles.sample, flagged_by: mod)
# User 1 - week 0
create_comment_time_ago(user1.id, 5.days.ago, commentable: articles.sample)
create_comment_time_ago(user1.id, 6.days.ago, commentable: articles.sample)
# User 1 - week 2
create_comment_time_ago(user1.id, 8.days.ago, commentable: articles.sample)
# User 1 - week 1
create_comment_time_ago(user1.id, 8.days.ago, commentable: articles.sample, flagged_by: mod)
create_comment_time_ago(user1.id, 11.days.ago, commentable: articles.sample)
# User 2 - week 1
create_comment_time_ago(user2.id, 4.days.ago, commentable: articles.sample)
create_comment_time_ago(user2.id, 6.days.ago, commentable: articles.sample)
# User 1 - week 2
create_comment_time_ago(user1.id, 15.days.ago, commentable: articles.sample)
create_comment_time_ago(user1.id, 15.days.ago, commentable: articles.sample)
# User 2 - week 0
create_comment_time_ago(user2.id, 1.day.ago, commentable: articles.sample)
# User 2 - week 1
create_comment_time_ago(user2.id, 9.days.ago, commentable: articles.sample)
create_comment_time_ago(user2.id, 13.days.ago, commentable: articles.sample, flagged_by: mod)
# User 1 - week 3
create_comment_time_ago(user2.id, 17.days.ago, commentable: articles.sample)
create_comment_time_ago(user2.id, 13.days.ago, commentable: articles.sample)
# User 2 - week 2
create_comment_time_ago(user2.id, 17.days.ago, commentable: articles.sample)
create_comment_time_ago(user2.id, 18.days.ago, commentable: articles.sample)
create_comment_time_ago(user2.id, 18.days.ago, commentable: articles.sample)
# User 2 - week 3
create_comment_time_ago(user2.id, 22.days.ago, commentable: articles.sample)
create_comment_time_ago(user2.id, 23.days.ago, commentable: articles.sample)
create_comment_time_ago(user2.id, 23.days.ago, commentable: articles.sample, flagged_by: mod)
end
it "matches the correct comment count for each week in result hash" do
@ -112,16 +123,17 @@ RSpec.describe Comments::CommunityWellnessQuery, type: :query do
# Result includes both users because they have > 1 comment per week
expect(result_user_ids).to contain_exactly(user1.id, user2.id)
# user1 must have `1` in first week comment count because one of their 2
# comments is flagged by a moderator
# user1 must have `1` in first week (1) comment count because one out of
# their two comments is flagged by a moderator
index1 = result.index { |hash| hash["user_id"] == user1.id }
expect(result[index1]["serialized_weeks_ago"]).to eq("1,2")
expect(result[index1]["serialized_comment_counts"]).to eq("1,2")
expect(result[index1]["serialized_weeks_ago"]).to eq("0,1,2")
expect(result[index1]["serialized_comment_counts"]).to eq("2,1,2")
# Second
# user1 must have `2` in third week (3) comment count because one out of
# their three comments is flagged by a moderator
index2 = result.index { |hash| hash["user_id"] == user2.id }
expect(result[index2]["serialized_weeks_ago"]).to eq("1,2,3")
expect(result[index2]["serialized_comment_counts"]).to eq("2,1,3")
expect(result[index2]["serialized_weeks_ago"]).to eq("0,1,2,3")
expect(result[index2]["serialized_comment_counts"]).to eq("1,2,3,2")
end
end
end

View file

@ -21,7 +21,7 @@ RSpec.describe Badges::AwardCommunityWellness, type: :service do
# Create 2 comments per-week to be tested, i.e. week 8 would create 2
# comments on each of the 8 weeks (calculated on days_ago per week)
reward_weeks[index].times do |week|
days_ago = (5 + (week * 7)).days.ago
days_ago = (8 + (week * 7)).days.ago
create_comment_time_ago(users[index].id, days_ago, commentable: articles.sample)
create_comment_time_ago(users[index].id, days_ago, commentable: articles.sample)
end