From 2005565c9cf2b0e24bd277d7ac74b7f7e2a3e7b3 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Wed, 6 Jul 2016 15:56:40 -0400 Subject: [PATCH] Server side code for Watching First Post Only --- app/models/category.rb | 1 + app/models/category_user.rb | 8 +++---- app/models/group_user.rb | 6 +++++ app/models/notification.rb | 8 ++----- app/models/tag_user.rb | 4 +++- app/models/topic.rb | 2 ++ app/models/topic_user.rb | 7 +++--- app/services/post_alerter.rb | 36 ++++++++++++++++++++++++++++ config/locales/client.en.yml | 2 ++ config/locales/server.en.yml | 16 ------------- lib/notification_levels.rb | 16 +++++++++++++ spec/integrity/i18n_spec.rb | 7 ------ spec/services/post_alerter_spec.rb | 38 ++++++++++++++++++++++++++++++ 13 files changed, 112 insertions(+), 39 deletions(-) create mode 100644 lib/notification_levels.rb diff --git a/app/models/category.rb b/app/models/category.rb index a120391f7..3ad7d5b51 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -17,6 +17,7 @@ class Category < ActiveRecord::Base belongs_to :latest_post, class_name: "Post" has_many :topics + has_many :category_users has_many :category_featured_topics has_many :featured_topics, through: :category_featured_topics, source: :topic diff --git a/app/models/category_user.rb b/app/models/category_user.rb index 44d555500..19d43b3d4 100644 --- a/app/models/category_user.rb +++ b/app/models/category_user.rb @@ -1,3 +1,5 @@ +require_dependency 'notification_levels' + class CategoryUser < ActiveRecord::Base belongs_to :category belongs_to :user @@ -11,11 +13,7 @@ class CategoryUser < ActiveRecord::Base end def self.notification_levels - @notification_levels ||= Enum.new(muted: 0, - regular: 1, - tracking: 2, - watching: 3, - watching_first_post: 4) + NotificationLevels.all end def self.watching_levels diff --git a/app/models/group_user.rb b/app/models/group_user.rb index 9c0c13306..df666a027 100644 --- a/app/models/group_user.rb +++ b/app/models/group_user.rb @@ -1,3 +1,5 @@ +require_dependency 'notification_levels' + class GroupUser < ActiveRecord::Base belongs_to :group, counter_cache: "user_count" belongs_to :user @@ -10,6 +12,10 @@ class GroupUser < ActiveRecord::Base after_save :grant_trust_level + def self.notification_levels + NotificationLevels.all + end + protected def set_primary_group diff --git a/app/models/notification.rb b/app/models/notification.rb index 072f78716..b9c05f24a 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -42,7 +42,8 @@ class Notification < ActiveRecord::Base invited_to_topic: 13, custom: 14, group_mentioned: 15, - group_message_summary: 16 + group_message_summary: 16, + watching_first_post: 17 ) end @@ -107,11 +108,6 @@ class Notification < ActiveRecord::Base end end - def text_description - link = block_given? ? yield : "" - I18n.t("notification_types.#{Notification.types[notification_type]}", data_hash.merge(link: link)) - end - def url topic.relative_url(post_number) if topic.present? end diff --git a/app/models/tag_user.rb b/app/models/tag_user.rb index 96244cf21..b988e918b 100644 --- a/app/models/tag_user.rb +++ b/app/models/tag_user.rb @@ -1,9 +1,11 @@ +require_dependency 'notification_levels' + class TagUser < ActiveRecord::Base belongs_to :tag belongs_to :user def self.notification_levels - TopicUser.notification_levels + NotificationLevels.all end def self.change(user_id, tag_id, level) diff --git a/app/models/topic.rb b/app/models/topic.rb index ade61d0cc..d810ba62a 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -79,6 +79,7 @@ class Topic < ActiveRecord::Base end belongs_to :category + has_many :category_users, through: :category has_many :posts has_many :ordered_posts, -> { order(post_number: :asc) }, class_name: "Post" has_many :topic_allowed_users @@ -94,6 +95,7 @@ class Topic < ActiveRecord::Base has_many :topic_tags, dependent: :destroy has_many :tags, through: :topic_tags + has_many :tag_users, through: :tags has_one :top_topic belongs_to :user diff --git a/app/models/topic_user.rb b/app/models/topic_user.rb index 3079385ee..5bac2ea42 100644 --- a/app/models/topic_user.rb +++ b/app/models/topic_user.rb @@ -1,3 +1,5 @@ +require_dependency 'notification_levels' + class TopicUser < ActiveRecord::Base belongs_to :user belongs_to :topic @@ -17,10 +19,7 @@ class TopicUser < ActiveRecord::Base # Enums def notification_levels - @notification_levels ||= Enum.new(muted: 0, - regular: 1, - tracking: 2, - watching: 3) + NotificationLevels.topic_levels end def notification_reasons diff --git a/app/services/post_alerter.rb b/app/services/post_alerter.rb index 8ba84ed33..bd194ea9b 100644 --- a/app/services/post_alerter.rb +++ b/app/services/post_alerter.rb @@ -107,6 +107,42 @@ class PostAlerter end sync_group_mentions(post, mentioned_groups) + + if post.post_number == 1 + topic = post.topic + + if topic.present? + cat_watchers = topic.category_users + .where(notification_level: CategoryUser.notification_levels[:watching_first_post]) + .pluck(:user_id) + + tag_watchers = topic.tag_users + .where(notification_level: TagUser.notification_levels[:watching_first_post]) + .pluck(:user_id) + + group_ids = post.user.groups.pluck(:id) + group_watchers = GroupUser.where(group_id: group_ids, + notification_level: GroupUser.notification_levels[:watching_first_post]) + .pluck(:user_id) + + watchers = [cat_watchers, tag_watchers, group_watchers].flatten + + notify_first_post_watchers(post, watchers) + end + end + end + + def notify_first_post_watchers(post, user_ids) + return if user_ids.blank? + + user_ids.uniq! + + # Don't notify the OP + user_ids -= [post.user_id] + + User.where(id: user_ids).each do |u| + create_notification(u, Notification.types[:watching_first_post], post) + end end def sync_group_mentions(post, mentioned_groups) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 911cd8c02..ac4440269 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1117,6 +1117,8 @@ en: linked: "

{{username}} {{description}}

" granted_badge: "

Earned '{{description}}'

" + watching_first_post: "

New Topic {{description}}

" + group_message_summary: one: "

{{count}} message in your {{group_name}} inbox

" other: "

{{count}} messages in your {{group_name}} inbox

" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index e0b91f001..ea013b7ad 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1383,22 +1383,6 @@ en: email_polling_disabled: "You must enable either manual or POP3 polling before enabling reply by email." user_locale_not_enabled: "You must first enable 'allow user locale' before enabling this setting." - notification_types: - group_mentioned: "%{group_name} was mentioned in %{link}" - mentioned: "%{display_username} mentioned you in %{link}" - liked: "%{display_username} liked your post in %{link}" - replied: "%{display_username} replied to your post in %{link}" - quoted: "%{display_username} quoted your post in %{link}" - edited: "%{display_username} edited your post in %{link}" - posted: "%{display_username} posted in %{link}" - moved_post: "%{display_username} moved your post to %{link}" - private_message: "%{display_username} sent you a message: %{link}" - invited_to_private_message: "%{display_username} invited you to a message: %{link}" - invited_to_topic: "%{display_username} invited you to %{link}" - invitee_accepted: "%{display_username} accepted your invitation" - linked: "%{display_username} linked you in %{link}" - granted_badge: "You earned %{link}" - search: within_post: "#%{post_number} by %{username}" types: diff --git a/lib/notification_levels.rb b/lib/notification_levels.rb new file mode 100644 index 000000000..a0e3aa9ef --- /dev/null +++ b/lib/notification_levels.rb @@ -0,0 +1,16 @@ +module NotificationLevels + def self.all + @all_levels ||= Enum.new(muted: 0, + regular: 1, + tracking: 2, + watching: 3, + watching_first_post: 4) + end + + def self.topic_levels + @topic_levels ||= Enum.new(muted: 0, + regular: 1, + tracking: 2, + watching: 3) + end +end diff --git a/spec/integrity/i18n_spec.rb b/spec/integrity/i18n_spec.rb index 099dd93ce..5a09c0ee2 100644 --- a/spec/integrity/i18n_spec.rb +++ b/spec/integrity/i18n_spec.rb @@ -23,13 +23,6 @@ describe "i18n integrity checks" do end end - it "needs an i18n key (notification_types) for each Notification type" do - Notification.types.each_key do |type| - next if type == :custom || type == :group_message_summary - expect(I18n.t("notification_types.#{type}")).not_to match(/translation missing/) - end - end - it "has valid YAML for client" do Dir["#{Rails.root}/config/locales/client.*.yml"].each do |f| locale = /.*\.([^.]{2,})\.yml$/.match(f)[1] diff --git a/spec/services/post_alerter_spec.rb b/spec/services/post_alerter_spec.rb index 6c2cc79b9..495c68c31 100644 --- a/spec/services/post_alerter_spec.rb +++ b/spec/services/post_alerter_spec.rb @@ -326,4 +326,42 @@ describe PostAlerter do end end + describe "watching_first_post" do + let(:group) { Fabricate(:group) } + let(:user) { Fabricate(:user) } + let(:category) { Fabricate(:category) } + let(:tag) { Fabricate(:tag) } + let(:topic) { Fabricate(:topic, category: category, tags: [tag]) } + let(:post) { Fabricate(:post, topic: topic) } + + it "doesn't notify people who aren't watching" do + PostAlerter.post_created(post) + expect(user.notifications.where(notification_type: Notification.types[:watching_first_post]).count).to eq(0) + end + + it "notifies the user who is following the first post category" do + level = CategoryUser.notification_levels[:watching_first_post] + CategoryUser.set_notification_level_for_category(user, level, category.id) + PostAlerter.post_created(post) + expect(user.notifications.where(notification_type: Notification.types[:watching_first_post]).count).to eq(1) + end + + it "notifies the user who is following the first post tag" do + level = TagUser.notification_levels[:watching_first_post] + TagUser.change(user.id, tag.id, level) + PostAlerter.post_created(post) + expect(user.notifications.where(notification_type: Notification.types[:watching_first_post]).count).to eq(1) + end + + it "notifies the user who is following the first post group" do + GroupUser.create(group_id: group.id, user_id: user.id) + GroupUser.create(group_id: group.id, user_id: post.user.id) + + level = GroupUser.notification_levels[:watching_first_post] + GroupUser.where(user_id: user.id, group_id: group.id).update_all(notification_level: level) + + PostAlerter.post_created(post) + expect(user.notifications.where(notification_type: Notification.types[:watching_first_post]).count).to eq(1) + end + end end