From 4ff9622bfc64911fa10435fb2fdedcdf00b63561 Mon Sep 17 00:00:00 2001 From: danielvincent Date: Sat, 25 Dec 2010 16:07:11 -0500 Subject: [PATCH] notifications now properly socket (not a hack through comments like before). notification badge updates on new messages. --- app/helpers/sockets_helper.rb | 25 ++++++++---------- app/models/notification.rb | 12 ++++++--- app/views/layouts/_header.html.haml | 5 ++-- app/views/notifications/_popup.haml | 6 +++++ app/views/shared/_notification.haml | 4 +++ public/javascripts/web-socket-receiver.js | 31 ++++++++++++++++------- public/stylesheets/sass/application.sass | 25 +++++++++--------- spec/models/notification_spec.rb | 29 +++++++++++++++------ 8 files changed, 86 insertions(+), 51 deletions(-) create mode 100644 app/views/notifications/_popup.haml diff --git a/app/helpers/sockets_helper.rb b/app/helpers/sockets_helper.rb index 6ce79653d..2c7ccc48a 100644 --- a/app/helpers/sockets_helper.rb +++ b/app/helpers/sockets_helper.rb @@ -4,6 +4,7 @@ module SocketsHelper include ApplicationHelper + include NotificationsHelper def obj_id(object) object.respond_to?(:post_id) ? object.post_id : object.id @@ -16,7 +17,7 @@ module SocketsHelper old_locale = I18n.locale I18n.locale = user.language.to_s end - + if object.is_a? StatusMessage post_hash = {:post => object, :person => object.person, @@ -32,15 +33,20 @@ module SocketsHelper v = render_to_string(:partial => 'shared/stream_element', :locals => post_hash) elsif object.is_a? Person person_hash = { - :single_aspect_form => opts["single_aspect_form"], + :single_aspect_form => opts["single_aspect_form"], :person => object, :aspects => user.aspects, :contact => user.contact_for(object), - :request => user.request_for(object), + :request => user.request_for(object), :current_user => user} v = render_to_string(:partial => 'people/person', :locals => person_hash) + elsif object.is_a? Comment v = render_to_string(:partial => 'comments/comment', :locals => {:hash => {:comment => object, :person => object.person}}) + + elsif object.is_a? Notification + v = render_to_string(:partial => 'notifications/popup', :locals => {:note => object, :person => object.person}) + else v = render_to_string(:partial => type_partial(object), :locals => {:post => object, :current_user => user}) unless object.is_a? Retraction end @@ -58,23 +64,14 @@ module SocketsHelper post = object.post action_hash[:comment_id] = object.id action_hash[:my_post?] = (post.person.owner.id == uid) - action_hash[:notification] = notification(object) action_hash[:post_guid] = post.id end action_hash[:mine?] = object.person && (object.person.owner.id == uid) if object.respond_to?(:person) - + I18n.locale = old_locale unless user.nil? - + action_hash.to_json end - - def notification(object) - begin - render_to_string(:partial => 'shared/notification', :locals => {:object => object}) - rescue Exception => e - Rails.logger.error("event=socket_render status=fail user=#{user.diaspora_handle} object=#{object.id.to_s}") - end - end end diff --git a/app/models/notification.rb b/app/models/notification.rb index 6282e4765..c4940e2ed 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -3,7 +3,9 @@ # the COPYRIGHT file. # class Notification + require File.join(Rails.root, 'lib/diaspora/web_socket') include MongoMapper::Document + include Diaspora::Socketable key :target_id, ObjectId key :kind, String @@ -23,10 +25,12 @@ class Notification def self.notify(user, object, person) if object.respond_to? :notification_type if kind = object.notification_type(user, person) - Notification.create(:target_id => object.id, - :kind => kind, - :person_id => person.id, - :user_id => user.id) + n = Notification.create(:target_id => object.id, + :kind => kind, + :person_id => person.id, + :user_id => user.id) + n.socket_to_uid(user.id) if n + n end end end diff --git a/app/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml index b4d46a281..d8c31f41d 100644 --- a/app/views/layouts/_header.html.haml +++ b/app/views/layouts/_header.html.haml @@ -25,9 +25,8 @@ #notification_badge = link_to "", notifications_path, :title => new_notification_text(@notification_count) = image_tag 'icons/mail_grey.png' - - if @notification_count > 0 - #notification_badge_number - = @notification_count + #notification_badge_number{:class => ("hidden" if @notification_count == 0)} + = @notification_count %ul#user_menu .right diff --git a/app/views/notifications/_popup.haml b/app/views/notifications/_popup.haml new file mode 100644 index 000000000..8293a4af9 --- /dev/null +++ b/app/views/notifications/_popup.haml @@ -0,0 +1,6 @@ +-# Copyright (c) 2010, Diaspora Inc. This file is +-# licensed under the Affero General Public License version 3 or later. See +-# the COPYRIGHT file. + += link_to "#{person.name.titleize}", person_path(person) += object_link(note) diff --git a/app/views/shared/_notification.haml b/app/views/shared/_notification.haml index 7547bcf10..7f99239f7 100644 --- a/app/views/shared/_notification.haml +++ b/app/views/shared/_notification.haml @@ -3,3 +3,7 @@ -# the COPYRIGHT file. = link_to t('.new', :type => object.class.to_s, :from => object.person.name), object_path(object.post) + + += link_to "#{note.person.name.titelize}", person_path(note.person) += object_link(note) diff --git a/public/javascripts/web-socket-receiver.js b/public/javascripts/web-socket-receiver.js index a71503908..4a1bdefe4 100644 --- a/public/javascripts/web-socket-receiver.js +++ b/public/javascripts/web-socket-receiver.js @@ -13,8 +13,8 @@ var WebSocketReceiver = { onMessage: function(evt) { var obj = jQuery.parseJSON(evt.data); - if(obj['notice']){ - WebSocketReceiver.processNotification(obj['notice']); + if(obj['class'] == 'notifications'){ + WebSocketReceiver.processNotification(obj); }else if (obj['class'] == 'people'){ WSR.debug("got a " + obj['class']); @@ -34,7 +34,8 @@ var WebSocketReceiver = { } } }, -processPerson: function(response){ + + processPerson: function(response){ form = $('.webfinger_form'); form.siblings('#loader').hide(); result_ul = form.siblings('#request_result'); @@ -52,8 +53,24 @@ processPerson: function(response){ }, - processNotification: function(html){ - $('#notification').html(html).fadeIn(200).delay(8000).fadeOut(200, function(){ $(this).html("");}); + processNotification: function(notification){ + + var nBadge = $("#notification_badge_number"); + + nBadge.html().replace(/\d+/, function(num){ + nBadge.html(parseInt(num)+1); + }); + + if(nBadge.hasClass("hidden")){ + nBadge.removeClass("hidden"); + } + + $('#notification').html(notification['html']) + .fadeIn(200) + .delay(8000) + .fadeOut(200, function(){ + $(this).html(""); + }); }, processRetraction: function(post_id){ @@ -86,10 +103,6 @@ processPerson: function(response){ $(".show_comments", post).removeClass('hidden'); } } - - if( !opts['mine?'] && opts['my_post?']) { - WebSocketReceiver.processNotification(opts['notification']); - } } }, diff --git a/public/stylesheets/sass/application.sass b/public/stylesheets/sass/application.sass index 74438963d..68cbe95d3 100644 --- a/public/stylesheets/sass/application.sass +++ b/public/stylesheets/sass/application.sass @@ -1523,22 +1523,21 @@ h3 span.current_gs_step :bottom 21px :right 12px - a - :background - :color rgb(30,30,30) - :color rgba(30,30,30,0.9) + :background + :color rgb(30,30,30) + :color rgba(30,30,30,0.9) - :-webkit-box-shadow 0 2px 3px #333 - :-moz-box-shadow 0 2px 3px #333 - :box-shadow 0 2px 3px #333 + :-webkit-box-shadow 0 2px 3px #333 + :-moz-box-shadow 0 2px 3px #333 + :box-shadow 0 2px 3px #333 - :-webkit-border-radius 5px - :border-radius 5px - :-moz-border-radius 5px + :-webkit-border-radius 5px + :border-radius 5px + :-moz-border-radius 5px - :min-width 200px - :padding 12px - :color #fff + :min-width 200px + :padding 12px + :color #fff .bottom_notification :position fixed diff --git a/spec/models/notification_spec.rb b/spec/models/notification_spec.rb index 3267554f4..16b8db5ee 100644 --- a/spec/models/notification_spec.rb +++ b/spec/models/notification_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' -describe Notification do +describe Notification do before do @sm = Factory(:status_message) @person = Factory(:person) @@ -31,11 +31,10 @@ describe Notification do describe '.for' do it 'returns all of a users notifications' do user2 = make_user - Notification.create(@opts) - Notification.create(@opts) - Notification.create(@opts) - Notification.create(@opts) - + 4.times do + Notification.create(@opts) + end + @opts.delete(:user_id) Notification.create(@opts.merge(:user_id => user2.id)) @@ -44,16 +43,30 @@ describe Notification do end describe '.notify' do - it ' does not call Notification.create if the object does not notification_type' do + it 'does not call Notification.create if the object does not notification_type' do Notification.should_not_receive(:create) Notification.notify(@user, @sm, @person) end - it ' does not call Notification.create if the object does not notification_type' do + it 'does call Notification.create if the object does not notification_type' do request = Request.instantiate(:from => @user.person, :to => @user2.person, :into => @aspect) Notification.should_receive(:create).once Notification.notify(@user, request, @person) end + + it 'sockets to the recipient' do + request = Request.instantiate(:from => @user.person, :to => @user2.person, :into => @aspect) + opts = {:target_id => request.id, + :kind => request.notification_type(@user, @person), + :person_id => @person.id, + :user_id => @user.id} + + n = Notification.create(opts) + Notification.stub!(:create).and_return n + + n.should_receive(:socket_to_uid).once + Notification.notify(@user, request, @person) + end end end