From a3f208c38031ee69e20af5cfcb86657bdfc95d27 Mon Sep 17 00:00:00 2001 From: cmrd Senya <senya@riseup.net> Date: Mon, 18 Jul 2016 17:58:12 +0000 Subject: [PATCH] Notifications and search page backend updates Updates introduce support for preloading contacts to Gon in order to support client-side rendering of aspect membership dropdown box. --- app/controllers/notifications_controller.rb | 10 ++-- app/controllers/people_controller.rb | 20 ++++---- app/helpers/aspect_global_helper.rb | 19 -------- app/helpers/gon_helper.rb | 8 ++++ app/models/notifications/started_sharing.rb | 4 ++ app/views/notifications/_notification.haml | 8 ++-- app/views/people/_person.html.haml | 2 +- app/views/people/_relationship_action.haml | 6 +-- .../notifications_controller_spec.rb | 2 +- spec/helpers/gon_helper_spec.rb | 48 +++++++++++++++++++ 10 files changed, 85 insertions(+), 42 deletions(-) create mode 100644 app/helpers/gon_helper.rb create mode 100644 spec/helpers/gon_helper_spec.rb diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb index 2d7a5f4ef0..984a381e71 100644 --- a/app/controllers/notifications_controller.rb +++ b/app/controllers/notifications_controller.rb @@ -38,9 +38,6 @@ class NotificationsController < ApplicationController pager.replace(result) end - @notifications.each do |note| - note.note_html = render_to_string( :partial => 'notification', :locals => { :note => note } ) - end @group_days = @notifications.group_by{|note| note.created_at.strftime('%Y-%m-%d')} @unread_notification_count = current_user.unread_notifications.count @@ -54,7 +51,12 @@ class NotificationsController < ApplicationController respond_to do |format| format.html format.xml { render :xml => @notifications.to_xml } - format.json { render :json => @notifications.to_json } + format.json { + @notifications.each do |note| + note.note_html = render_to_string(partial: "notification", locals: {note: note, no_aspect_dropdown: true}) + end + render json: @notifications.to_json + } end end diff --git a/app/controllers/people_controller.rb b/app/controllers/people_controller.rb index 09cc4bc0c0..5029ccc62f 100644 --- a/app/controllers/people_controller.rb +++ b/app/controllers/people_controller.rb @@ -3,6 +3,8 @@ # the COPYRIGHT file. class PeopleController < ApplicationController + include GonHelper + before_action :authenticate_user!, except: %i(show stream hovercard) before_action :find_person, only: %i(show stream hovercard) @@ -168,16 +170,14 @@ class PeopleController < ApplicationController end def hashes_for_people(people, aspects) - ids = people.map{|p| p.id} - contacts = {} - Contact.unscoped.where(:user_id => current_user.id, :person_id => ids).each do |contact| - contacts[contact.person_id] = contact - end - - people.map{|p| - {:person => p, - :contact => contacts[p.id], - :aspects => aspects} + people.map {|person| + { + person: person, + contact: current_user.contact_for(person) || Contact.new(person: person), + aspects: aspects + }.tap {|hash| + gon_load_contact(hash[:contact]) + } } end diff --git a/app/helpers/aspect_global_helper.rb b/app/helpers/aspect_global_helper.rb index a35ce7fd22..421215b7d2 100644 --- a/app/helpers/aspect_global_helper.rb +++ b/app/helpers/aspect_global_helper.rb @@ -3,25 +3,6 @@ # the COPYRIGHT file. module AspectGlobalHelper - def aspect_membership_dropdown(contact, person, hang) - aspect_membership_ids = {} - - selected_aspects = all_aspects.select{|aspect| contact.in_aspect?(aspect)} - selected_aspects.each do |a| - record = a.aspect_memberships.find { |am| am.contact_id == contact.id } - aspect_membership_ids[a.id] = record.id - end - - button_class = selected_aspects.size > 0 ? "btn-success" : "btn-default" - - render "aspect_memberships/aspect_membership_dropdown", - :selected_aspects => selected_aspects, - :aspect_membership_ids => aspect_membership_ids, - :person => person, - :hang => hang, - :button_class => button_class - end - def aspect_options_for_select(aspects) options = {} aspects.each do |aspect| diff --git a/app/helpers/gon_helper.rb b/app/helpers/gon_helper.rb new file mode 100644 index 0000000000..f4bb9689d0 --- /dev/null +++ b/app/helpers/gon_helper.rb @@ -0,0 +1,8 @@ +module GonHelper + def gon_load_contact(contact) + Gon.preloads[:contacts] ||= [] + if Gon.preloads[:contacts].none? {|stored_contact| stored_contact[:person][:id] == contact.person_id } + Gon.preloads[:contacts] << ContactPresenter.new(contact, current_user).full_hash_with_person + end + end +end diff --git a/app/models/notifications/started_sharing.rb b/app/models/notifications/started_sharing.rb index c80ad88a97..bae3a3a1ea 100644 --- a/app/models/notifications/started_sharing.rb +++ b/app/models/notifications/started_sharing.rb @@ -12,5 +12,9 @@ module Notifications sender = contact.person create_notification(contact.user_id, sender, sender).email_the_user(sender, sender) end + + def contact + recipient.contact_for(target) + end end end diff --git a/app/views/notifications/_notification.haml b/app/views/notifications/_notification.haml index 7a76decd92..0302216467 100644 --- a/app/views/notifications/_notification.haml +++ b/app/views/notifications/_notification.haml @@ -1,9 +1,11 @@ .media.stream_element{:data=>{:guid => note.id, :type => (Notification.types.key(note.type) || '') }, :class => (note.unread ? 'unread' : 'read')} .unread-toggle.pull-right %i.entypo-eye{title: (note.unread ? t("notifications.index.mark_read") : t("notifications.index.mark_unread"))} - - if note.type == "Notifications::StartedSharing" && contact = current_user.contact_for(note.target) - .pull-right - = aspect_membership_dropdown(contact, note.target, "right") + - if note.type == "Notifications::StartedSharing" && (!defined?(no_aspect_dropdown) || !no_aspect_dropdown) + - if note.target.present? + - gon_load_contact(note.contact) + .pull-right + .aspect_membership_dropdown.placeholder{data: {person_id: note.target.id}} .media-object.pull-left = person_image_link note.actors.first, :size => :thumb_small, :class => 'hovercardable' diff --git a/app/views/people/_person.html.haml b/app/views/people/_person.html.haml index 3c008b339b..48e543d2da 100644 --- a/app/views/people/_person.html.haml +++ b/app/views/people/_person.html.haml @@ -1,7 +1,7 @@ .media.stream_element{id: person.id} .pull-right = render partial: 'people/relationship_action', - locals: { person: person, contact: contact, + locals: { person: person, :current_user => current_user } .media-object.pull-left = person_image_link(person, size: :thumb_small) diff --git a/app/views/people/_relationship_action.haml b/app/views/people/_relationship_action.haml index 4685760603..01593dec7f 100644 --- a/app/views/people/_relationship_action.haml +++ b/app/views/people/_relationship_action.haml @@ -1,7 +1,5 @@ - unless person == current_user.person - - contact = current_user.contacts.find_by_person_id(person.id) - - contact ||= Contact.new(:person => person) - .aspect_membership_dropdown + .aspect_membership_dropdown.placeholder{data: {person_id: person.id}} -else %span.thats_you - = t('people.person.thats_you') + = t("people.person.thats_you") diff --git a/spec/controllers/notifications_controller_spec.rb b/spec/controllers/notifications_controller_spec.rb index bc98c798b0..5bb68ccb01 100644 --- a/spec/controllers/notifications_controller_spec.rb +++ b/spec/controllers/notifications_controller_spec.rb @@ -111,7 +111,7 @@ describe NotificationsController, :type => :controller do eve.share_with(alice.person, eve.aspects.first) get :index, "per_page" => 5 - expect(Nokogiri(response.body).css(".aspect_membership")).not_to be_empty + expect(Nokogiri(response.body).css(".aspect_membership_dropdown")).not_to be_empty end it 'succeeds on mobile' do diff --git a/spec/helpers/gon_helper_spec.rb b/spec/helpers/gon_helper_spec.rb new file mode 100644 index 0000000000..c449c91260 --- /dev/null +++ b/spec/helpers/gon_helper_spec.rb @@ -0,0 +1,48 @@ +require "spec_helper" + +describe GonHelper, type: :helper do + include_context :gon + + describe "#gon_load_contact" do + let(:contact) { FactoryGirl.build(:contact) } + let(:current_user) { contact.user } + let(:another_contact) { FactoryGirl.build(:contact, user: current_user) } + + before do + RequestStore.store[:gon] = Gon::Request.new(controller.request.env) + Gon.preloads = {} + end + + it "calls appropriate presenter" do + expect_any_instance_of(ContactPresenter).to receive(:full_hash_with_person) + gon_load_contact(contact) + end + + shared_examples "contacts loading" do + it "loads contacts to gon" do + gon_load_contact(contact) + gon_load_contact(another_contact) + expect(Gon.preloads[:contacts].count).to eq(2) + end + + it "avoids duplicates" do + gon_load_contact(contact) + gon_load_contact(contact) + expect(Gon.preloads[:contacts].count).to eq(1) + end + end + + context "with non-persisted contacts" do + include_examples "contacts loading" + end + + context "with persisted contacts" do + before do + contact.save! + another_contact.save! + end + + include_examples "contacts loading" + end + end +end -- GitLab