Commit 23f8a40ad66b3578db9c70948734741303bdf926

Authored by David Silva
Committed by Rodrigo Souto
1 parent d1f72816

invite: allow network member/friend invitation

This feature allows organizations to invite people and users to request
friendship from other users from the network instead of only through
email.

Signed-off-by: Rodrigo Souto <rodrigo@colivre.coop.br>
Signed-off-by: Andre Bernardes <andrebsguedes@gmail.com>
Signed-off-by: Fabio Teixeira <fabio1079@gmail.com>
Signed-off-by: Pedro de Lyra  <pedrodelyra@gmail.com>
app/controllers/public/invite_controller.rb
@@ -11,7 +11,7 @@ class InviteController &lt; PublicController @@ -11,7 +11,7 @@ class InviteController &lt; PublicController
11 labels = Profile::SEARCHABLE_FIELDS.except(:nickname).merge(User::SEARCHABLE_FIELDS).map { |name,info| info[:label].downcase } 11 labels = Profile::SEARCHABLE_FIELDS.except(:nickname).merge(User::SEARCHABLE_FIELDS).map { |name,info| info[:label].downcase }
12 last = labels.pop 12 last = labels.pop
13 label = labels.join(', ') 13 label = labels.join(', ')
14 - @search_friend_fields = "#{label} #{_('or')} #{last}" 14 + @search_fields = "#{label} #{_('or')} #{last}"
15 15
16 if request.post? 16 if request.post?
17 contact_list = ContactList.create 17 contact_list = ContactList.create
@@ -78,8 +78,12 @@ class InviteController &lt; PublicController @@ -78,8 +78,12 @@ class InviteController &lt; PublicController
78 end 78 end
79 end 79 end
80 80
81 - def search_friend  
82 - render :text => find_by_contents(:people, environment, environment.people.not_members_of(profile), params['q'], {:page => 1}, {:joins => :user})[:results].map {|person| {:id => person.id, :name => person.name} }.to_json 81 + def search
  82 + scope = profile.invite_friends_only ? user.friends : environment.people
  83 + scope = scope.not_members_of(profile) if profile.organization?
  84 + scope = scope.not_friends_of(profile) if profile.person?
  85 + results = find_by_contents(:people, environment, scope, params['q'], {:page => 1}, {:joins => :user})[:results]
  86 + render :text => prepare_to_token_input(results).to_json
83 end 87 end
84 88
85 protected 89 protected
app/views/friends/index.html.erb
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> 16 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>
17 <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %> 17 <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %>
18 <% unless @plugins.dispatch(:remove_invite_friends_button).include?(true) %> 18 <% unless @plugins.dispatch(:remove_invite_friends_button).include?(true) %>
19 - <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'invite_friends') %> 19 + <%= button(:search, _('Invite people'), :controller => 'invite', :action => 'invite_friends') %>
20 <% end %> 20 <% end %>
21 <% end %> 21 <% end %>
22 22
app/views/invite/invite_friends.html.erb
1 <% if profile.person? %> 1 <% if profile.person? %>
2 - <h1><%= _('Invite your friends') %></h1> 2 + <h1><%= _('Ask for friendship') %></h1>
  3 + <% description = _('You can search for user profiles and ask them to become your friends.') %>
3 <% else %> 4 <% else %>
4 <h1><%= _('Invite your friends to join %s') % profile.name %></h1> 5 <h1><%= _('Invite your friends to join %s') % profile.name %></h1>
  6 + <% description = _('You can search for user profiles and invite them to join this group.') %>
5 <% end %> 7 <% end %>
6 8
7 -<% if profile.community? %>  
8 - <h2><%= _('Invite registered users') %></h2>  
9 - <p><%= _('You can search for user profiles and invite them to join this community.') %></p> 9 +<h3>
  10 + <%= _("Choose person by:") %>
  11 +</h3>
  12 +
  13 +<p>
  14 + <%= labelled_radio_button _("Name"), :invite_friend_by, 1, true, :id => "invite_friend_by_name", :class => "invite_friend_by" %>
  15 + <%= labelled_radio_button _("Email"), :invite_friend_by, 2, false, :id => "invite_friend_by_email", :class => "invite_friend_by" %>
  16 +</p>
  17 +
  18 +<div class='invite_by_name'>
  19 + <p><%= description %></p>
10 <%= form_tag :action => 'invite_registered_friend' do %> 20 <%= form_tag :action => 'invite_registered_friend' do %>
11 - <% search_action = url_for(:action => 'search_friend') %>  
12 - <%= token_input_field_tag(:q, 'search-friends', search_action,  
13 - { :hint_text => _('Type in your friend\'s %{search_fields}') % {:search_fields => @search_friend_fields},  
14 - :focus => false }) %> 21 + <% search_action = url_for(:action => 'search') %>
  22 + <%= token_input_field_tag(
  23 + :q, 'search-people', search_action,
  24 + { :hint_text => _('Type in the person\'s %{search_fields}') % {:search_fields => @search_fields},
  25 + :focus => false }) %>
15 26
16 <% button_bar do %> 27 <% button_bar do %>
17 <%= submit_button('save', _('Invite'))%> 28 <%= submit_button('save', _('Invite'))%>
18 <%= button('cancel', _('Cancel'), profile.url)%> 29 <%= button('cancel', _('Cancel'), profile.url)%>
19 <% end %> 30 <% end %>
20 <% end %> 31 <% end %>
  32 +</div>
21 33
22 - <br /> 34 +<div class='invite_by_email' style="display: none;">
23 <h2><%= _('Invite people from my e-mail contacts') %></h2> 35 <h2><%= _('Invite people from my e-mail contacts') %></h2>
24 <% header = 'h3' %> 36 <% header = 'h3' %>
25 37
26 -<% end %>  
27 -  
28 <%= render :partial => 'invite/select_address_book', :locals => {:header => header} %> 38 <%= render :partial => 'invite/select_address_book', :locals => {:header => header} %>
  39 +</div>
29 40
30 <div id="loadingScreen"></div> 41 <div id="loadingScreen"></div>
  42 +<%= javascript_include_tag 'invite' %>
app/views/profile/friends.html.erb
@@ -18,7 +18,7 @@ @@ -18,7 +18,7 @@
18 <%= button :back, _('Go back'), { :controller => 'profile' } %> 18 <%= button :back, _('Go back'), { :controller => 'profile' } %>
19 <% if user == profile %> 19 <% if user == profile %>
20 <%= button :edit, _('Manage my friends'), :controller => 'friends', :action => 'index', :profile => profile.identifier %> 20 <%= button :edit, _('Manage my friends'), :controller => 'friends', :action => 'index', :profile => profile.identifier %>
21 - <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'invite_friends') %> 21 + <%= button(:search, _('Invite people'), :controller => 'invite', :action => 'invite_friends') %>
22 <% end %> 22 <% end %>
23 <% end %> 23 <% end %>
24 24
features/invitation.feature
@@ -17,25 +17,22 @@ Feature: invitation @@ -17,25 +17,22 @@ Feature: invitation
17 17
18 Scenario: see link to invite friends 18 Scenario: see link to invite friends
19 When I am on /profile/josesilva/friends 19 When I am on /profile/josesilva/friends
20 - Then I should see "Invite people from my e-mail contacts" link 20 + Then I should see "Invite people" link
21 21
22 Scenario: see link to invite friends in myprofile 22 Scenario: see link to invite friends in myprofile
23 When I am on /myprofile/josesilva/friends 23 When I am on /myprofile/josesilva/friends
24 - Then I should see "Invite people from my e-mail contacts" link 24 + Then I should see "Invite people" link
25 25
26 Scenario: go to invitation screen when follow link to invite friends 26 Scenario: go to invitation screen when follow link to invite friends
27 Given I am on /myprofile/josesilva/friends 27 Given I am on /myprofile/josesilva/friends
28 - When I follow "Invite people from my e-mail contacts" 28 + When I follow "Invite people"
29 Then I am on /profile/josesilva/invite/friends 29 Then I am on /profile/josesilva/invite/friends
30 30
31 - Scenario: see title when invite friends  
32 - When I am on /profile/josesilva/invite/friends  
33 - Then I should see "Invite your friends"  
34 -  
35 @selenium 31 @selenium
36 Scenario: back to friends after invite friends 32 Scenario: back to friends after invite friends
37 Given I am on /myprofile/josesilva/friends 33 Given I am on /myprofile/josesilva/friends
38 - And I follow "Invite people from my e-mail contacts" 34 + And I follow "Invite people"
  35 + And I choose "Email"
39 And I press "Next" 36 And I press "Next"
40 And I fill in "manual_import_addresses" with "misfits@devil.doll" 37 And I fill in "manual_import_addresses" with "misfits@devil.doll"
41 And I follow "Personalize invitation mail" 38 And I follow "Personalize invitation mail"
@@ -77,7 +74,8 @@ Feature: invitation @@ -77,7 +74,8 @@ Feature: invitation
77 @selenium 74 @selenium
78 Scenario: back to members after invite friends to join a community 75 Scenario: back to members after invite friends to join a community
79 Given I am on 26 Bsslines's members management 76 Given I am on 26 Bsslines's members management
80 - And I follow "Invite your friends to join 26 Bsslines" 77 + And I follow "Invite people"
  78 + And I choose "Email"
81 And I press "Next" 79 And I press "Next"
82 And I fill in "manual_import_addresses" with "misfits@devil.doll" 80 And I fill in "manual_import_addresses" with "misfits@devil.doll"
83 And I follow "Personalize invitation mail" 81 And I follow "Personalize invitation mail"
@@ -88,7 +86,8 @@ Feature: invitation @@ -88,7 +86,8 @@ Feature: invitation
88 @selenium 86 @selenium
89 Scenario: noosfero user receives a task when a user invites to join a community 87 Scenario: noosfero user receives a task when a user invites to join a community
90 Given I am on 26 Bsslines's members management 88 Given I am on 26 Bsslines's members management
91 - And I follow "Invite your friends to join 26 Bsslines" 89 + And I follow "Invite people"
  90 + And I choose "Email"
92 And I press "Next" 91 And I press "Next"
93 And I fill in "manual_import_addresses" with "santos@invalid.br" 92 And I fill in "manual_import_addresses" with "santos@invalid.br"
94 And I follow "Personalize invitation mail" 93 And I follow "Personalize invitation mail"
@@ -133,7 +132,8 @@ Feature: invitation @@ -133,7 +132,8 @@ Feature: invitation
133 Scenario: noosfero user receives a task when a user invites to be friend 132 Scenario: noosfero user receives a task when a user invites to be friend
134 Given I am on josesilva's control panel 133 Given I am on josesilva's control panel
135 And I follow "Manage friends" 134 And I follow "Manage friends"
136 - And I follow "Invite people from my e-mail contacts" 135 + And I follow "Invite people"
  136 + And I choose "Email"
137 And I press "Next" 137 And I press "Next"
138 And I fill in "manual_import_addresses" with "santos@invalid.br" 138 And I fill in "manual_import_addresses" with "santos@invalid.br"
139 And I follow "Personalize invitation mail" 139 And I follow "Personalize invitation mail"
features/step_definitions/invitation_steps.rb
@@ -2,6 +2,7 @@ Given /^I invite email &quot;(.+)&quot; to join community &quot;(.+)&quot;$/ do |email, community| @@ -2,6 +2,7 @@ Given /^I invite email &quot;(.+)&quot; to join community &quot;(.+)&quot;$/ do |email, community|
2 identifier = Community.find_by_name(community).identifier 2 identifier = Community.find_by_name(community).identifier
3 visit("/myprofile/#{identifier}/profile_members") 3 visit("/myprofile/#{identifier}/profile_members")
4 first(:link, "Invite your friends to join #{community}").click 4 first(:link, "Invite your friends to join #{community}").click
  5 + choose("Email")
5 click_button('Next') 6 click_button('Next')
6 fill_in('manual_import_addresses', :with => "#{email}") 7 fill_in('manual_import_addresses', :with => "#{email}")
7 click_link('Personalize invitation mail') 8 click_link('Personalize invitation mail')
@@ -11,7 +12,8 @@ end @@ -11,7 +12,8 @@ end
11 12
12 Given /^I invite email "(.+)" to be my friend$/ do |email| 13 Given /^I invite email "(.+)" to be my friend$/ do |email|
13 click_link('Manage friends') 14 click_link('Manage friends')
14 - click_link('Invite people from my e-mail contacts') 15 + click_link('Invite people')
  16 + choose("Email")
15 click_button('Next') 17 click_button('Next')
16 fill_in('manual_import_addresses', :with => "#{email}") 18 fill_in('manual_import_addresses', :with => "#{email}")
17 click_link('Personalize invitation mail') 19 click_link('Personalize invitation mail')
public/javascripts/invite.js 0 → 100644
@@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
  1 +(function($){
  2 + 'use strict';
  3 +
  4 + function toggle_invitation_method() {
  5 + if (+(this.value) === 1) {
  6 + $('.invite_by_email').hide();
  7 + $('.invite_by_name').show();
  8 + } else {
  9 + $('.invite_by_name').hide();
  10 + $('.invite_by_email').show();
  11 + }
  12 + }
  13 +
  14 + function manage_members_moderation() {
  15 + var checked = $('#profile_data_allow_members_to_invite').is(':checked');
  16 +
  17 + if (checked) {
  18 + $('.invite_friends_only').show();
  19 + } else {
  20 + $('.invite_friends_only').hide();
  21 + }
  22 + }
  23 +
  24 + function hide_invite_friend_login_password() {
  25 + $('#invite-friends-login-password').hide();
  26 + }
  27 +
  28 + function show_invite_friend_login_password() {
  29 + if (this.value === 'hotmail') {
  30 + $('#hotmail_username_tip').show();
  31 + } else {
  32 + $('#hotmail_username_tip').hide();
  33 + }
  34 +
  35 + $('#invite-friends-login-password').show();
  36 + $('#login').focus();
  37 + }
  38 +
  39 + $(document).ready(function() {
  40 + $('.invite_by_email').hide();
  41 + manage_members_moderation();
  42 +
  43 + // Event triggers
  44 + $('.invite_friend_by').click(toggle_invitation_method);
  45 +
  46 + $("#import_from_manual").click(hide_invite_friend_login_password);
  47 +
  48 + $('.invite_by_this_email').click(show_invite_friend_login_password);
  49 +
  50 + $('#profile_data_allow_members_to_invite').click(manage_members_moderation);
  51 + });
  52 +})(jQuery);
test/functional/invite_controller_test.rb
@@ -101,7 +101,6 @@ class InviteControllerTest &lt; ActionController::TestCase @@ -101,7 +101,6 @@ class InviteControllerTest &lt; ActionController::TestCase
101 should 'display invitation page' do 101 should 'display invitation page' do
102 get :invite_friends, :profile => profile.identifier 102 get :invite_friends, :profile => profile.identifier
103 assert_response :success 103 assert_response :success
104 - assert_tag :tag => 'h1', :content => 'Invite your friends'  
105 end 104 end
106 105
107 should 'get mail template to invite members' do 106 should 'get mail template to invite members' do
@@ -243,18 +242,18 @@ class InviteControllerTest &lt; ActionController::TestCase @@ -243,18 +242,18 @@ class InviteControllerTest &lt; ActionController::TestCase
243 friend1.save 242 friend1.save
244 friend2.save 243 friend2.save
245 244
246 - get :search_friend, :profile => profile.identifier, :q => 'me@' 245 + get :search, :profile => profile.identifier, :q => 'me@'
247 246
248 assert_equal 'text/html', @response.content_type 247 assert_equal 'text/html', @response.content_type
249 assert_equal [{"id" => friend2.id, "name" => friend2.name}].to_json, @response.body 248 assert_equal [{"id" => friend2.id, "name" => friend2.name}].to_json, @response.body
250 249
251 - get :search_friend, :profile => profile.identifier, :q => 'cri' 250 + get :search, :profile => profile.identifier, :q => 'cri'
252 251
253 assert_equal [{"id" => friend1.id, "name" => friend1.name}].to_json, @response.body 252 assert_equal [{"id" => friend1.id, "name" => friend1.name}].to_json, @response.body
254 253
255 - get :search_friend, :profile => profile.identifier, :q => 'will' 254 + get :search, :profile => profile.identifier, :q => 'will'
256 255
257 - assert_equal [{"id" => friend1.id, "name" => friend1.name}, {"id" => friend2.id, "name" => friend2.name}].to_json, @response.body 256 + assert_equivalent [{"id" => friend1.id, "name" => friend1.name}, {"id" => friend2.id, "name" => friend2.name}], json_response
258 end 257 end
259 258
260 should 'not include members in search friends profiles' do 259 should 'not include members in search friends profiles' do
@@ -266,11 +265,25 @@ class InviteControllerTest &lt; ActionController::TestCase @@ -266,11 +265,25 @@ class InviteControllerTest &lt; ActionController::TestCase
266 265
267 community.add_member(friend2) 266 community.add_member(friend2)
268 267
269 - get :search_friend, :profile => community.identifier, :q => 'will' 268 + get :search, :profile => community.identifier, :q => 'will'
270 269
271 assert_equivalent [{"name" => friend1.name, "id" => friend1.id}], json_response 270 assert_equivalent [{"name" => friend1.name, "id" => friend1.id}], json_response
272 end 271 end
273 272
  273 + should 'not include friends in search for people to request friendship' do
  274 + friend1 = create_user('willy').person
  275 + friend2 = create_user('william').person
  276 +
  277 + profile.add_friend friend1
  278 + friend1.add_friend profile
  279 + profile.add_friend friend2
  280 + friend2.add_friend profile
  281 +
  282 + get :search, :profile => profile.identifier, :q => 'will'
  283 +
  284 + assert_empty json_response
  285 + end
  286 +
274 should 'invite registered users through profile id' do 287 should 'invite registered users through profile id' do
275 friend1 = create_user('testuser1').person 288 friend1 = create_user('testuser1').person
276 friend2 = create_user('testuser2').person 289 friend2 = create_user('testuser2').person