# Copyright (c) 2010-2011, Diaspora Inc. This file is # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. # class Notification < ActiveRecord::Base belongs_to :recipient, class_name: "User" has_many :notification_actors, dependent: :destroy has_many :actors, class_name: "Person", through: :notification_actors, source: :person belongs_to :target, polymorphic: true attr_accessor :note_html def self.for(recipient, opts={}) where(opts.merge!(recipient_id: recipient.id)).order("updated_at DESC") end def self.notify(recipient, target, actor) return nil unless target.respond_to?(:notification_type) && recipient.person != actor note_type = target.notification_type(recipient, actor) return nil unless note_type return_note = if [Comment, Like, Reshare].any? { |klass| target.is_a?(klass) } s_target = target.is_a?(Reshare) ? target.root : target.parent note_type.concatenate_or_create(recipient, s_target, actor, note_type) else note_type.make_notification(recipient, target, actor, note_type) end return_note.email_the_user(target, actor) if return_note return_note end def as_json(opts={}) super(opts.merge(methods: :note_html)) end def email_the_user(target, actor) recipient.mail(mail_job, recipient_id, actor.id, target.id) end def set_read_state( read_state ) update_column(:unread, !read_state) end def mail_job raise NotImplementedError.new("Subclass this.") end def linked_object target end def self.concatenate_or_create(recipient, target, actor, notification_type) return nil if suppress_notification?(recipient, target) if n = notification_type.where(:target_id => target.id, :target_type => target.class.base_class, :recipient_id => recipient.id, :unread => true).first begin n.actors = n.actors | [actor] n.unread = true # Explicitly touch the notification to update updated_at whenever new actor is inserted in notification. n.touch n.save! rescue ActiveRecord::RecordNotUnique nil end n else make_notification(recipient, target, actor, notification_type) end end def self.make_notification(recipient, target, actor, notification_type) return nil if suppress_notification?(recipient, target) n = notification_type.new(:target => target, :recipient_id => recipient.id) n.actors = n.actors | [actor] n.unread = false if target.is_a? Request n.save! n end def self.concatenate_or_create(recipient, target, actor) return nil if suppress_notification?(recipient, target) find_or_initialize_by(recipient: recipient, target: target, unread: true).tap do |notification| notification.actors |= [actor] # Explicitly touch the notification to update updated_at whenever new actor is inserted in notification. if notification.new_record? || notification.changed? notification.save! else notification.touch end end end def self.create_notification(recipient_id, target, actor) create(recipient_id: recipient_id, target: target, actors: [actor]) end def self.suppress_notification?(recipient, post) post.is_a?(Post) && recipient.is_shareable_hidden?(post) end private_class_method :suppress_notification? def self.types { "also_commented" => "Notifications::AlsoCommented", "comment_on_post" => "Notifications::CommentOnPost", "liked" => "Notifications::Liked", "mentioned" => "Notifications::Mentioned", "reshared" => "Notifications::Reshared", "started_sharing" => "Notifications::StartedSharing" } end end