From 484c97fc8d2bbf8d06ce3451e4347a332f7720dd Mon Sep 17 00:00:00 2001 From: Vaidehi Joshi Date: Mon, 5 Apr 2021 18:19:46 -0700 Subject: [PATCH] Limit mentions in posts (#13259) * Limit mentions in articles * Bump MAX_USER_MENTION_LIVE_AT to April 7th, 2021 UTC time * Use stubbed constants in article and comment specs * Add TODOs around extracting MAX_USER_MENTIONS into constant --- app/models/article.rb | 17 +++++++++++++++++ app/models/comment.rb | 3 +++ spec/models/article_spec.rb | 27 +++++++++++++++++++++++++++ spec/models/comment_spec.rb | 10 +++++----- 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/app/models/article.rb b/app/models/article.rb index 135be27c5..7722e9016 100644 --- a/app/models/article.rb +++ b/app/models/article.rb @@ -30,6 +30,12 @@ class Article < ApplicationRecord counter_culture :user counter_culture :organization + # TODO: Vaidehi Joshi - Extract this into a constant or SiteConfig variable + # after https://github.com/forem/rfcs/pull/22 has been completed? + MAX_USER_MENTIONS = 7 # Explicitly set to 7 to accommodate DEV Top 7 Posts + # The date that we began limiting the number of user mentions in an article. + MAX_USER_MENTION_LIVE_AT = Time.utc(2021, 4, 7).freeze + has_many :comments, as: :commentable, inverse_of: :commentable, dependent: :nullify has_many :html_variant_successes, dependent: :nullify has_many :html_variant_trials, dependent: :nullify @@ -80,6 +86,7 @@ class Article < ApplicationRecord validate :validate_collection_permission validate :validate_tag validate :validate_video + validate :user_mentions_in_markdown validate :validate_co_authors, unless: -> { co_author_ids.blank? } validate :validate_co_authors_must_not_be_the_same, unless: -> { co_author_ids.blank? } validate :validate_co_authors_exist, unless: -> { co_author_ids.blank? } @@ -629,6 +636,16 @@ class Article < ApplicationRecord errors.add(:canonical_url, "must not have spaces") end + def user_mentions_in_markdown + return if created_at.present? && created_at.before?(MAX_USER_MENTION_LIVE_AT) + + # The "comment-mentioned-user" css is added by Html::Parser#user_link_if_exists + mentions_count = Nokogiri::HTML(processed_html).css(".comment-mentioned-user").size + return if mentions_count <= MAX_USER_MENTIONS + + errors.add(:base, "You cannot mention more than #{MAX_USER_MENTIONS} users in a post!") + end + def create_slug if slug.blank? && title.present? && !published self.slug = title_to_slug + "-temp-slug-#{rand(10_000_000)}" diff --git a/app/models/comment.rb b/app/models/comment.rb index edaaee6ce..ff4a329c5 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -12,6 +12,9 @@ class Comment < ApplicationRecord COMMENTABLE_TYPES = %w[Article PodcastEpisode].freeze TITLE_DELETED = "[deleted]".freeze TITLE_HIDDEN = "[hidden by post author]".freeze + + # TODO: Vaidehi Joshi - Extract this into a constant or SiteConfig variable + # after https://github.com/forem/rfcs/pull/22 has been completed? MAX_USER_MENTIONS = 7 # Explicitly set to 7 to accommodate DEV Top 7 Posts # The date that we began limiting the number of user mentions in a comment. MAX_USER_MENTION_LIVE_AT = Time.utc(2021, 3, 12).freeze diff --git a/spec/models/article_spec.rb b/spec/models/article_spec.rb index 4b7ac4eeb..7891e3d57 100644 --- a/spec/models/article_spec.rb +++ b/spec/models/article_spec.rb @@ -1091,6 +1091,33 @@ RSpec.describe Article, type: :model do end end + describe "#user_mentions_in_markdown" do + before do + stub_const("Article::MAX_USER_MENTIONS", 7) + stub_const("Article::MAX_USER_MENTION_LIVE_AT", 1.day.ago) # Set live_at date to a time in the past + end + + it "is valid with any number of mentions if created before MAX_USER_MENTION_LIVE_AT date" do + # Explicitly set created_at date to a time before MAX_USER_MENTION_LIVE_AT + article = create(:article, created_at: 3.days.ago) + + article.body_markdown = "hi @#{user.username}! " * (Article::MAX_USER_MENTIONS + 1) + expect(article).to be_valid + end + + it "is valid with seven or fewer mentions if created after MAX_USER_MENTION_LIVE_AT date" do + article.body_markdown = "hi @#{user.username}! " * Article::MAX_USER_MENTIONS + expect(article).to be_valid + end + + it "is invalid with more than seven mentions if created after MAX_USER_MENTION_LIVE_AT date" do + article.body_markdown = "hi @#{user.username}! " * (Article::MAX_USER_MENTIONS + 1) + expect(article).not_to be_valid + expect(article.errors[:base]) + .to include("You cannot mention more than #{Article::MAX_USER_MENTIONS} users in a post!") + end + end + describe "#update_score" do it "stably sets the correct blackbox values" do create(:reaction, reactable: article, points: 1) diff --git a/spec/models/comment_spec.rb b/spec/models/comment_spec.rb index f2a053fb1..387f2c9b8 100644 --- a/spec/models/comment_spec.rb +++ b/spec/models/comment_spec.rb @@ -85,7 +85,7 @@ RSpec.describe Comment, type: :model do end end - describe "#mention_total" do + describe "#user_mentions_in_markdown" do before do stub_const("Comment::MAX_USER_MENTIONS", 7) stub_const("Comment::MAX_USER_MENTION_LIVE_AT", 1.day.ago) # Set live_at date to a time in the past @@ -96,24 +96,24 @@ RSpec.describe Comment, type: :model do subject.created_at = 3.days.ago subject.commentable_type = "Article" - subject.body_markdown = "hi @#{user.username}! " * 8 + subject.body_markdown = "hi @#{user.username}! " * (Comment::MAX_USER_MENTIONS + 1) expect(subject).to be_valid end it "is valid with seven or fewer mentions if created after MAX_USER_MENTION_LIVE_AT date" do subject.commentable_type = "Article" - subject.body_markdown = "hi @#{user.username}! " * 7 + subject.body_markdown = "hi @#{user.username}! " * Comment::MAX_USER_MENTIONS expect(subject).to be_valid end it "is invalid with more than seven mentions if created after MAX_USER_MENTION_LIVE_AT date" do subject.commentable_type = "Article" - subject.body_markdown = "hi @#{user.username}! " * 8 + subject.body_markdown = "hi @#{user.username}! " * (Comment::MAX_USER_MENTIONS + 1) expect(subject).not_to be_valid expect(subject.errors[:base]) - .to include("You cannot mention more than 7 users in a comment!") + .to include("You cannot mention more than #{Comment::MAX_USER_MENTIONS} users in a comment!") end end # rubocop:enable RSpec/NamedSubject