Server side code for Watching First Post Only

This commit is contained in:
Robin Ward 2016-07-06 15:56:40 -04:00
parent 1eb64151f6
commit 2005565c9c
13 changed files with 112 additions and 39 deletions

View File

@ -17,6 +17,7 @@ class Category < ActiveRecord::Base
belongs_to :latest_post, class_name: "Post" belongs_to :latest_post, class_name: "Post"
has_many :topics has_many :topics
has_many :category_users
has_many :category_featured_topics has_many :category_featured_topics
has_many :featured_topics, through: :category_featured_topics, source: :topic has_many :featured_topics, through: :category_featured_topics, source: :topic

View File

@ -1,3 +1,5 @@
require_dependency 'notification_levels'
class CategoryUser < ActiveRecord::Base class CategoryUser < ActiveRecord::Base
belongs_to :category belongs_to :category
belongs_to :user belongs_to :user
@ -11,11 +13,7 @@ class CategoryUser < ActiveRecord::Base
end end
def self.notification_levels def self.notification_levels
@notification_levels ||= Enum.new(muted: 0, NotificationLevels.all
regular: 1,
tracking: 2,
watching: 3,
watching_first_post: 4)
end end
def self.watching_levels def self.watching_levels

View File

@ -1,3 +1,5 @@
require_dependency 'notification_levels'
class GroupUser < ActiveRecord::Base class GroupUser < ActiveRecord::Base
belongs_to :group, counter_cache: "user_count" belongs_to :group, counter_cache: "user_count"
belongs_to :user belongs_to :user
@ -10,6 +12,10 @@ class GroupUser < ActiveRecord::Base
after_save :grant_trust_level after_save :grant_trust_level
def self.notification_levels
NotificationLevels.all
end
protected protected
def set_primary_group def set_primary_group

View File

@ -42,7 +42,8 @@ class Notification < ActiveRecord::Base
invited_to_topic: 13, invited_to_topic: 13,
custom: 14, custom: 14,
group_mentioned: 15, group_mentioned: 15,
group_message_summary: 16 group_message_summary: 16,
watching_first_post: 17
) )
end end
@ -107,11 +108,6 @@ class Notification < ActiveRecord::Base
end end
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 def url
topic.relative_url(post_number) if topic.present? topic.relative_url(post_number) if topic.present?
end end

View File

@ -1,9 +1,11 @@
require_dependency 'notification_levels'
class TagUser < ActiveRecord::Base class TagUser < ActiveRecord::Base
belongs_to :tag belongs_to :tag
belongs_to :user belongs_to :user
def self.notification_levels def self.notification_levels
TopicUser.notification_levels NotificationLevels.all
end end
def self.change(user_id, tag_id, level) def self.change(user_id, tag_id, level)

View File

@ -79,6 +79,7 @@ class Topic < ActiveRecord::Base
end end
belongs_to :category belongs_to :category
has_many :category_users, through: :category
has_many :posts has_many :posts
has_many :ordered_posts, -> { order(post_number: :asc) }, class_name: "Post" has_many :ordered_posts, -> { order(post_number: :asc) }, class_name: "Post"
has_many :topic_allowed_users has_many :topic_allowed_users
@ -94,6 +95,7 @@ class Topic < ActiveRecord::Base
has_many :topic_tags, dependent: :destroy has_many :topic_tags, dependent: :destroy
has_many :tags, through: :topic_tags has_many :tags, through: :topic_tags
has_many :tag_users, through: :tags
has_one :top_topic has_one :top_topic
belongs_to :user belongs_to :user

View File

@ -1,3 +1,5 @@
require_dependency 'notification_levels'
class TopicUser < ActiveRecord::Base class TopicUser < ActiveRecord::Base
belongs_to :user belongs_to :user
belongs_to :topic belongs_to :topic
@ -17,10 +19,7 @@ class TopicUser < ActiveRecord::Base
# Enums # Enums
def notification_levels def notification_levels
@notification_levels ||= Enum.new(muted: 0, NotificationLevels.topic_levels
regular: 1,
tracking: 2,
watching: 3)
end end
def notification_reasons def notification_reasons

View File

@ -107,6 +107,42 @@ class PostAlerter
end end
sync_group_mentions(post, mentioned_groups) 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 end
def sync_group_mentions(post, mentioned_groups) def sync_group_mentions(post, mentioned_groups)

View File

@ -1117,6 +1117,8 @@ en:
linked: "<i title='linked post' class='fa fa-link'></i><p><span>{{username}}</span> {{description}}</p>" linked: "<i title='linked post' class='fa fa-link'></i><p><span>{{username}}</span> {{description}}</p>"
granted_badge: "<i title='badge granted' class='fa fa-certificate'></i><p>Earned '{{description}}'</p>" granted_badge: "<i title='badge granted' class='fa fa-certificate'></i><p>Earned '{{description}}'</p>"
watching_first_post: "<i title='new topic' class='fa fa-dot-circle-o'></i><p><span>New Topic</span> {{description}}</p>"
group_message_summary: group_message_summary:
one: "<i title='messages in group inbox' class='fa fa-group'></i><p> {{count}} message in your {{group_name}} inbox</p>" one: "<i title='messages in group inbox' class='fa fa-group'></i><p> {{count}} message in your {{group_name}} inbox</p>"
other: "<i title='messages in group inbox' class='fa fa-group'></i><p> {{count}} messages in your {{group_name}} inbox</p>" other: "<i title='messages in group inbox' class='fa fa-group'></i><p> {{count}} messages in your {{group_name}} inbox</p>"

View File

@ -1383,22 +1383,6 @@ en:
email_polling_disabled: "You must enable either manual or POP3 polling before enabling reply by email." 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." 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: search:
within_post: "#%{post_number} by %{username}" within_post: "#%{post_number} by %{username}"
types: types:

View File

@ -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

View File

@ -23,13 +23,6 @@ describe "i18n integrity checks" do
end end
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 it "has valid YAML for client" do
Dir["#{Rails.root}/config/locales/client.*.yml"].each do |f| Dir["#{Rails.root}/config/locales/client.*.yml"].each do |f|
locale = /.*\.([^.]{2,})\.yml$/.match(f)[1] locale = /.*\.([^.]{2,})\.yml$/.match(f)[1]

View File

@ -326,4 +326,42 @@ describe PostAlerter do
end end
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 end