2013-03-01 07:07:44 -05:00
|
|
|
require_dependency 'enum'
|
2013-02-07 10:45:24 -05:00
|
|
|
|
2013-03-01 07:07:44 -05:00
|
|
|
class Notification < ActiveRecord::Base
|
2013-02-05 14:16:51 -05:00
|
|
|
belongs_to :user
|
|
|
|
belongs_to :topic
|
|
|
|
|
|
|
|
validates_presence_of :data
|
|
|
|
validates_presence_of :notification_type
|
|
|
|
|
2013-02-28 13:54:12 -05:00
|
|
|
scope :unread, lambda { where(read: false) }
|
2014-02-13 01:12:17 -05:00
|
|
|
scope :recent, lambda {|n=nil| n ||= 10; order('created_at desc').limit(n) }
|
2013-02-28 13:54:12 -05:00
|
|
|
|
2013-05-16 01:03:03 -04:00
|
|
|
after_save :refresh_notification_count
|
|
|
|
after_destroy :refresh_notification_count
|
|
|
|
|
2013-05-16 03:50:14 -04:00
|
|
|
def self.ensure_consistency!
|
|
|
|
Notification.exec_sql("
|
|
|
|
DELETE FROM Notifications n WHERE notification_type = :id AND
|
|
|
|
NOT EXISTS(
|
|
|
|
SELECT 1 FROM posts p
|
|
|
|
JOIN topics t ON t.id = p.topic_id
|
|
|
|
WHERE p.deleted_at is null AND t.deleted_at IS NULL
|
|
|
|
AND p.post_number = n.post_number AND t.id = n.topic_id
|
|
|
|
)" , id: Notification.types[:private_message])
|
|
|
|
end
|
|
|
|
|
2013-03-01 07:07:44 -05:00
|
|
|
def self.types
|
|
|
|
@types ||= Enum.new(
|
|
|
|
:mentioned, :replied, :quoted, :edited, :liked, :private_message,
|
2014-03-17 22:12:07 -04:00
|
|
|
:invited_to_private_message, :invitee_accepted, :posted, :moved_post,
|
2014-04-16 15:59:45 -04:00
|
|
|
:linked, :granted_badge
|
2013-03-01 07:07:44 -05:00
|
|
|
)
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
2013-02-25 02:42:42 -05:00
|
|
|
def self.mark_posts_read(user, topic_id, post_numbers)
|
2013-07-01 14:45:52 -04:00
|
|
|
Notification.where(user_id: user.id, topic_id: topic_id, post_number: post_numbers, read: false).update_all "read = 't'"
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.interesting_after(min_date)
|
|
|
|
result = where("created_at > ?", min_date)
|
|
|
|
.includes(:topic)
|
|
|
|
.unread
|
|
|
|
.limit(20)
|
2013-03-01 07:07:44 -05:00
|
|
|
.order("CASE WHEN notification_type = #{Notification.types[:replied]} THEN 1
|
|
|
|
WHEN notification_type = #{Notification.types[:mentioned]} THEN 2
|
2013-02-05 14:16:51 -05:00
|
|
|
ELSE 3
|
|
|
|
END, created_at DESC").to_a
|
|
|
|
|
|
|
|
# Remove any duplicates by type and topic
|
|
|
|
if result.present?
|
2013-02-07 10:45:24 -05:00
|
|
|
seen = {}
|
2013-02-05 14:16:51 -05:00
|
|
|
to_remove = Set.new
|
|
|
|
|
|
|
|
result.each do |r|
|
|
|
|
seen[r.notification_type] ||= Set.new
|
|
|
|
if seen[r.notification_type].include?(r.topic_id)
|
2013-02-07 10:45:24 -05:00
|
|
|
to_remove << r.id
|
2013-02-05 14:16:51 -05:00
|
|
|
else
|
|
|
|
seen[r.notification_type] << r.topic_id
|
|
|
|
end
|
|
|
|
end
|
2013-02-07 10:45:24 -05:00
|
|
|
result.reject! {|r| to_remove.include?(r.id) }
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
# Be wary of calling this frequently. O(n) JSON parsing can suck.
|
|
|
|
def data_hash
|
|
|
|
@data_hash ||= begin
|
|
|
|
return nil if data.blank?
|
2013-02-28 13:54:12 -05:00
|
|
|
JSON.parse(data).with_indifferent_access
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def text_description
|
|
|
|
link = block_given? ? yield : ""
|
2013-03-01 07:07:44 -05:00
|
|
|
I18n.t("notification_types.#{Notification.types[notification_type]}", data_hash.merge(link: link))
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def url
|
|
|
|
if topic.present?
|
|
|
|
return topic.relative_url(post_number)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def post
|
2013-02-28 13:54:12 -05:00
|
|
|
return if topic_id.blank? || post_number.blank?
|
2013-02-05 14:16:51 -05:00
|
|
|
|
|
|
|
Post.where(topic_id: topic_id, post_number: post_number).first
|
|
|
|
end
|
2013-05-16 01:03:03 -04:00
|
|
|
|
2014-02-13 01:12:17 -05:00
|
|
|
def self.recent_report(user, count = nil)
|
2014-02-13 15:20:56 -05:00
|
|
|
count ||= 10
|
2014-02-13 01:27:35 -05:00
|
|
|
notifications = user.notifications.recent(count).includes(:topic).to_a
|
2014-02-13 01:12:17 -05:00
|
|
|
|
|
|
|
if notifications.present?
|
|
|
|
notifications += user.notifications
|
|
|
|
.order('created_at desc')
|
|
|
|
.where(read: false, notification_type: Notification.types[:private_message])
|
|
|
|
.where('id < ?', notifications.last.id)
|
|
|
|
.limit(count)
|
|
|
|
|
2014-02-13 01:27:35 -05:00
|
|
|
notifications.sort do |x,y|
|
|
|
|
if x.unread_pm? && !y.unread_pm?
|
|
|
|
-1
|
|
|
|
elsif y.unread_pm? && !x.unread_pm?
|
|
|
|
1
|
|
|
|
else
|
|
|
|
y.created_at <=> x.created_at
|
|
|
|
end
|
|
|
|
end.take(count)
|
|
|
|
else
|
|
|
|
[]
|
|
|
|
end
|
2014-02-13 01:12:17 -05:00
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
def unread_pm?
|
|
|
|
Notification.types[:private_message] == self.notification_type && !read
|
|
|
|
end
|
2013-05-16 01:03:03 -04:00
|
|
|
|
|
|
|
protected
|
|
|
|
|
|
|
|
def refresh_notification_count
|
|
|
|
user_id = user.id
|
|
|
|
MessageBus.publish("/notification/#{user_id}",
|
|
|
|
{unread_notifications: user.unread_notifications,
|
|
|
|
unread_private_messages: user.unread_private_messages},
|
|
|
|
user_ids: [user_id] # only publish the notification to this user
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
2013-05-23 22:48:32 -04:00
|
|
|
# == Schema Information
|
|
|
|
#
|
|
|
|
# Table name: notifications
|
|
|
|
#
|
|
|
|
# id :integer not null, primary key
|
|
|
|
# notification_type :integer not null
|
|
|
|
# user_id :integer not null
|
|
|
|
# data :string(1000) not null
|
|
|
|
# read :boolean default(FALSE), not null
|
2014-04-15 01:53:48 -04:00
|
|
|
# created_at :datetime not null
|
|
|
|
# updated_at :datetime not null
|
2013-05-23 22:48:32 -04:00
|
|
|
# topic_id :integer
|
|
|
|
# post_number :integer
|
|
|
|
# post_action_id :integer
|
|
|
|
#
|
|
|
|
# Indexes
|
|
|
|
#
|
|
|
|
# index_notifications_on_post_action_id (post_action_id)
|
|
|
|
# index_notifications_on_user_id_and_created_at (user_id,created_at)
|
|
|
|
#
|