ReplyingComments: add tests, fix on deleted, less gas
Fixes showing replies for comments that were deleted or moderated. Doesn't show replies if the parent commenter has flagged the replier in the thread.
This commit is contained in:
parent
a0078521e1
commit
a4af5a18f8
|
@ -0,0 +1,5 @@
|
|||
class UpdateReplyingCommentsToVersion8 < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
update_view :replying_comments, version: 8, revert_to_version: 7
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2018_12_02_194809) do
|
||||
ActiveRecord::Schema.define(version: 2019_05_29_133507) do
|
||||
|
||||
create_table "comments", id: :bigint, unsigned: true, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t|
|
||||
t.datetime "created_at", null: false
|
||||
|
@ -332,7 +332,7 @@ ActiveRecord::Schema.define(version: 2018_12_02_194809) do
|
|||
add_foreign_key "votes", "users", name: "votes_user_id_fk"
|
||||
|
||||
create_view "replying_comments", sql_definition: <<-SQL
|
||||
select `read_ribbons`.`user_id` AS `user_id`,`comments`.`id` AS `comment_id`,`read_ribbons`.`story_id` AS `story_id`,`comments`.`parent_comment_id` AS `parent_comment_id`,`comments`.`created_at` AS `comment_created_at`,`parent_comments`.`user_id` AS `parent_comment_author_id`,`comments`.`user_id` AS `comment_author_id`,`stories`.`user_id` AS `story_author_id`,`read_ribbons`.`updated_at` < `comments`.`created_at` AS `is_unread`,(select `votes`.`vote` from `votes` where `votes`.`user_id` = `read_ribbons`.`user_id` and `votes`.`comment_id` = `comments`.`id`) AS `current_vote_vote`,(select `votes`.`reason` from `votes` where `votes`.`user_id` = `read_ribbons`.`user_id` and `votes`.`comment_id` = `comments`.`id`) AS `current_vote_reason` from (((`read_ribbons` join `comments` on(`comments`.`story_id` = `read_ribbons`.`story_id`)) join `stories` on(`stories`.`id` = `comments`.`story_id`)) left join `comments` `parent_comments` on(`parent_comments`.`id` = `comments`.`parent_comment_id`)) where `read_ribbons`.`is_following` = 1 and `comments`.`user_id` <> `read_ribbons`.`user_id` and `comments`.`is_deleted` = 0 and `comments`.`is_moderated` = 0 and (`parent_comments`.`user_id` = `read_ribbons`.`user_id` or `parent_comments`.`user_id` is null and `stories`.`user_id` = `read_ribbons`.`user_id`) and `comments`.`upvotes` - `comments`.`downvotes` >= 0 and (`parent_comments`.`id` is null or `parent_comments`.`upvotes` - `parent_comments`.`downvotes` >= 0) and cast(`stories`.`upvotes` as signed) - cast(`stories`.`downvotes` as signed) >= 0
|
||||
select `read_ribbons`.`user_id` AS `user_id`,`comments`.`id` AS `comment_id`,`read_ribbons`.`story_id` AS `story_id`,`comments`.`parent_comment_id` AS `parent_comment_id`,`comments`.`created_at` AS `comment_created_at`,`parent_comments`.`user_id` AS `parent_comment_author_id`,`comments`.`user_id` AS `comment_author_id`,`stories`.`user_id` AS `story_author_id`,`read_ribbons`.`updated_at` < `comments`.`created_at` AS `is_unread`,(select `votes`.`vote` from `votes` where `votes`.`user_id` = `read_ribbons`.`user_id` and `votes`.`comment_id` = `comments`.`id`) AS `current_vote_vote`,(select `votes`.`reason` from `votes` where `votes`.`user_id` = `read_ribbons`.`user_id` and `votes`.`comment_id` = `comments`.`id`) AS `current_vote_reason` from (((`read_ribbons` join `comments` on(`comments`.`story_id` = `read_ribbons`.`story_id`)) join `stories` on(`stories`.`id` = `comments`.`story_id`)) left join `comments` `parent_comments` on(`parent_comments`.`id` = `comments`.`parent_comment_id`)) where `read_ribbons`.`is_following` = 1 and `comments`.`user_id` <> `read_ribbons`.`user_id` and `comments`.`is_deleted` = 0 and `comments`.`is_moderated` = 0 and (`parent_comments`.`user_id` = `read_ribbons`.`user_id` or `parent_comments`.`user_id` is null and `stories`.`user_id` = `read_ribbons`.`user_id`) and `comments`.`upvotes` - `comments`.`downvotes` >= 0 and (`parent_comments`.`id` is null or `parent_comments`.`upvotes` - `parent_comments`.`downvotes` >= 0 and `parent_comments`.`is_moderated` = 0 and `parent_comments`.`is_deleted` = 0) and !exists(select 1 from (`votes` `f` join `comments` `c` on(`f`.`comment_id` = `c`.`id`)) where `f`.`vote` < 0 and `f`.`user_id` = `parent_comments`.`user_id` and `c`.`user_id` = `comments`.`user_id` and `f`.`story_id` = `comments`.`story_id`) and cast(`stories`.`upvotes` as signed) - cast(`stories`.`downvotes` as signed) >= 0
|
||||
SQL
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
SELECT
|
||||
read_ribbons.user_id,
|
||||
comments.id as comment_id,
|
||||
read_ribbons.story_id as story_id,
|
||||
comments.parent_comment_id,
|
||||
comments.created_at as comment_created_at,
|
||||
parent_comments.user_id as parent_comment_author_id,
|
||||
comments.user_id as comment_author_id,
|
||||
stories.user_id as story_author_id,
|
||||
(read_ribbons.updated_at < comments.created_at) as is_unread,
|
||||
(select votes.vote from votes where votes.user_id = read_ribbons.user_id and votes.comment_id = comments.id) as current_vote_vote,
|
||||
(select votes.reason from votes where votes.user_id = read_ribbons.user_id and votes.comment_id = comments.id) as current_vote_reason
|
||||
FROM
|
||||
read_ribbons
|
||||
JOIN
|
||||
comments ON comments.story_id = read_ribbons.story_id
|
||||
JOIN
|
||||
stories ON stories.id = comments.story_id
|
||||
LEFT JOIN
|
||||
comments parent_comments ON parent_comments.id = comments.parent_comment_id
|
||||
WHERE
|
||||
read_ribbons.is_following = 1
|
||||
AND comments.user_id != read_ribbons.user_id
|
||||
AND comments.is_deleted = FALSE
|
||||
AND comments.is_moderated = FALSE
|
||||
AND (
|
||||
parent_comments.user_id = read_ribbons.user_id
|
||||
OR (parent_comments.user_id IS NULL
|
||||
AND stories.user_id = read_ribbons.user_id)
|
||||
)
|
||||
AND (comments.upvotes - comments.downvotes) >= 0 -- comment doesn't have negative score
|
||||
AND (
|
||||
parent_comments.id IS NULL
|
||||
OR (
|
||||
-- parent doesn't have negative score, isn't deleted, isn't moderated
|
||||
(parent_comments.upvotes - parent_comments.downvotes) >= 0
|
||||
AND parent_comments.is_moderated = FALSE
|
||||
AND parent_comments.is_deleted = FALSE
|
||||
)
|
||||
)
|
||||
AND ( -- parent user has not flagged replier in the thread
|
||||
NOT EXISTS (
|
||||
SELECT 1 FROM votes f JOIN comments c ON f.comment_id = c.id
|
||||
WHERE
|
||||
f.vote < 0
|
||||
AND f.user_id = parent_comments.user_id
|
||||
AND c.user_id = comments.user_id
|
||||
AND f.story_id = comments.story_id
|
||||
)
|
||||
)
|
||||
AND (CAST(stories.upvotes as signed) - CAST(stories.downvotes as signed)) >= 0
|
||||
;
|
|
@ -1,5 +1,6 @@
|
|||
FactoryBot.define do
|
||||
factory :vote do
|
||||
association(:user)
|
||||
vote { 1 }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec::Matchers.define :have_reply do |expected|
|
||||
match do |actual|
|
||||
ReplyingComment.for_user(actual.user).map(&:comment).include? expected
|
||||
end
|
||||
|
||||
failure_message do |actual|
|
||||
"expected that comment #{actual.id} would be in " \
|
||||
"#{ReplyingComment.for_user(expected.user).map(&:comment_id)}"
|
||||
end
|
||||
end
|
||||
|
||||
describe ReplyingComment do
|
||||
def followed_parent
|
||||
p = create(:comment)
|
||||
ReadRibbon.create(user_id: p.user_id, story_id: p.story_id, updated_at: p.created_at - 1.second)
|
||||
p
|
||||
end
|
||||
|
||||
def flag_comment(comment, by = create(:user))
|
||||
Vote.vote_thusly_on_story_or_comment_for_user_because(
|
||||
-1, comment.story_id, comment.id, by.id, 'T'
|
||||
)
|
||||
end
|
||||
|
||||
describe "is listed when" do
|
||||
it "it's a direct reply" do
|
||||
p = followed_parent
|
||||
c = create(:comment, story_id: p.story_id, parent_comment: p)
|
||||
|
||||
expect(p).to have_reply(c)
|
||||
end
|
||||
end
|
||||
|
||||
describe "is not listed when" do
|
||||
it "parent has a negative score" do
|
||||
p = followed_parent
|
||||
flag_comment(p)
|
||||
flag_comment(p)
|
||||
c = create(:comment, story_id: p.story_id, parent_comment: p)
|
||||
|
||||
expect(p).to_not have_reply(c)
|
||||
end
|
||||
|
||||
it "it has a negative score" do
|
||||
p = followed_parent
|
||||
c = create(:comment, story_id: p.story_id, parent_comment: p)
|
||||
flag_comment(c)
|
||||
flag_comment(c)
|
||||
|
||||
expect(p).to_not have_reply(c)
|
||||
end
|
||||
|
||||
it "parent is deleted" do
|
||||
p = followed_parent
|
||||
c = create(:comment, story_id: p.story_id, parent_comment: p)
|
||||
p.delete_for_user(p.user)
|
||||
|
||||
expect(p).to_not have_reply(c)
|
||||
end
|
||||
|
||||
it "it is deleted" do
|
||||
p = followed_parent
|
||||
c = create(:comment, story_id: p.story_id, parent_comment: p)
|
||||
c.delete_for_user(c.user)
|
||||
|
||||
expect(p).to_not have_reply(c)
|
||||
end
|
||||
|
||||
it "parent is moderated" do
|
||||
p = followed_parent
|
||||
c = create(:comment, story_id: p.story_id, parent_comment: p)
|
||||
p.delete_for_user(create(:user, :admin), "obvs because I disagree with your politics")
|
||||
|
||||
expect(p).to_not have_reply(c)
|
||||
end
|
||||
|
||||
it "it is moderated" do
|
||||
p = followed_parent
|
||||
c = create(:comment, story_id: p.story_id, parent_comment: p)
|
||||
c.delete_for_user(create(:user, :admin), "obvs because I disagree with your politics")
|
||||
|
||||
expect(p).to_not have_reply(c)
|
||||
end
|
||||
|
||||
it "it is on a story with a negative score" do
|
||||
p = followed_parent
|
||||
c = create(:comment, story_id: p.story_id, parent_comment: p)
|
||||
Vote.vote_thusly_on_story_or_comment_for_user_because(
|
||||
-1, p.story_id, nil, create(:user).id, 'O'
|
||||
)
|
||||
Vote.vote_thusly_on_story_or_comment_for_user_because(
|
||||
-1, p.story_id, nil, create(:user).id, 'O'
|
||||
)
|
||||
|
||||
expect(p.story.reload.score).to be < 0
|
||||
expect(p).to_not have_reply(c)
|
||||
end
|
||||
|
||||
it "commenter has not flagged child commenter in the story" do
|
||||
p = followed_parent
|
||||
c = create(:comment, story_id: p.story_id, parent_comment: p)
|
||||
|
||||
expect(p).to have_reply(c)
|
||||
|
||||
flag_comment(c, p.user)
|
||||
expect(p).to_not have_reply(c)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue