Commit fb93be11927efb74816bb2b84f89a29c563df2e2

Authored by Larissa Reis
1 parent b429b47a

Improved registered users invitation using the user interface

app/controllers/public/invite_controller.rb
... ... @@ -4,8 +4,9 @@ class InviteController < PublicController
4 4 before_filter :login_required
5 5 before_filter :check_permissions_to_invite
6 6  
7   - def select_address_book
  7 + def invite_friends
8 8 @import_from = params[:import_from] || "manual"
  9 + @mail_template = params[:mail_template] || environment.invitation_mail_template(profile)
9 10 if request.post?
10 11 contact_list = ContactList.create
11 12 Delayed::Job.enqueue GetEmailContactsJob.new(@import_from, params[:login], params[:password], contact_list.id) if @import_from != 'manual'
... ... @@ -52,7 +53,32 @@ class InviteController < PublicController
52 53 def cancel_fetching_emails
53 54 contact_list = ContactList.find(params[:contact_list])
54 55 contact_list.destroy
55   - redirect_to :action => 'select_address_book'
  56 + redirect_to :action => 'invite_friends'
  57 + end
  58 +
  59 + def invite_registered_friend
  60 + contacts_to_invite = params['q'].split(',')
  61 + mail_template = params[:mail_template] || environment.invitation_mail_template(profile)
  62 + if !contacts_to_invite.empty?
  63 + Delayed::Job.enqueue InvitationJob.new(current_user.person.id, contacts_to_invite, mail_template, profile.id, nil, locale)
  64 + session[:notice] = _('Your invitations are being sent.')
  65 + if profile.person?
  66 + redirect_to :controller => 'profile', :action => 'friends'
  67 + else
  68 + redirect_to :controller => 'profile', :action => 'members'
  69 + end
  70 + return
  71 + else
  72 + redirect_to :action => 'invite_friends'
  73 + session[:notice] = _('Please enter a valid profile.')
  74 + end
  75 + end
  76 +
  77 + def search_friend
  78 + fields = %w[name identifier email]
  79 + values = ["%#{params['q']}%"] * fields.count
  80 + render :text => environment.people.find(:all, :joins => ['INNER JOIN users ON profiles.user_id=users.id'], :conditions => [fields.map {|field| "LOWER(#{field}) LIKE ?"}.join(' OR '), *values]).
  81 + map {|person| {:id => person.id, :name => person.name} }.to_json
56 82 end
57 83  
58 84 protected
... ...
app/views/friends/index.rhtml
... ... @@ -15,7 +15,7 @@
15 15 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>
16 16 <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %>
17 17 <% unless @plugins.dispatch(:remove_invite_friends_button).include?(true) %>
18   - <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'select_address_book') %>
  18 + <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'invite_friends') %>
19 19 <% end %>
20 20 <% end %>
21 21 <% end %>
... ... @@ -46,7 +46,7 @@
46 46 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>
47 47 <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %>
48 48 <% unless @plugins.dispatch(:remove_invite_friends_button).include?(true) %>
49   - <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'select_address_book') %>
  49 + <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'invite_friends') %>
50 50 <% end %>
51 51 <% end %>
52 52 <% end %>
... ...
app/views/invite/_personalize_invitation_mail.rhtml 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +<br/>
  2 +
  3 +<%= link_to_function(_('Personalize invitation mail'), nil) do |page|
  4 + page['invitation-mail_template'].show
  5 +end %>
  6 +
  7 +<div id='invitation-mail_template' style='display:none'>
  8 + <%= h _("Now enter an invitation message. You must keep the <url> code in your invitation text. When your friends receive the invitation e-mail, <url> will be replaced by a link that they need to click to activate their account. <user> and <friend> codes will be replaced by your name and friend name, but they are optional.") %>
  9 + <%= labelled_form_field(_('Invitation text:'), text_area_tag(:mail_template, mail_template, :cols => 72, :rows => 8)) %>
  10 +</div>
... ...
app/views/invite/_select_address_book.rhtml 0 → 100644
... ... @@ -0,0 +1,40 @@
  1 +<h2><%= _('Step 1 of 2: Select address book') %></h2>
  2 +
  3 +<% form_tag do %>
  4 +
  5 + <%= [
  6 + radio_button_tag(:import_from, "manual", @import_from == "manual", :onclick => 'hide_invite_friend_login_password()') + content_tag('label', _('Manually (empty field)'), :for => "import_from_manual"),
  7 + radio_button_tag(:import_from, "gmail", @import_from == "gmail", :onclick => 'show_invite_friend_login_password(this.value)') + content_tag('label', 'Gmail', :for => 'import_from_gmail'),
  8 + radio_button_tag(:import_from, "yahoo", @import_from == "yahoo", :onclick => 'show_invite_friend_login_password(this.value)') + content_tag('label', 'Yahoo', :for => "import_from_yahoo"),
  9 + radio_button_tag(:import_from, "hotmail", @import_from == "hotmail", :onclick => 'show_invite_friend_login_password(this.value)') + content_tag('label', 'Hotmail', :for => "import_from_hotmail")
  10 + ].join("\n<br/>\n") %>
  11 +
  12 + <script type="text/javascript">
  13 + function hide_invite_friend_login_password() {
  14 + $('invite-friends-login-password').hide();
  15 + }
  16 + function show_invite_friend_login_password(option) {
  17 + if (option == 'hotmail') {
  18 + $('hotmail_username_tip').show();
  19 + } else {
  20 + $('hotmail_username_tip').hide();
  21 + }
  22 + $('invite-friends-login-password').show();
  23 + $('login').focus();
  24 + }
  25 + </script>
  26 + <div id='invite-friends-login-password' <%= "style='display: none;'" if (@import_from == 'manual') %>>
  27 + <div id='hotmail_username_tip'>
  28 + <%= ui_icon('ui-icon-alert') %>
  29 + <%= _('Please type your username in the format yourname@example.com') %>
  30 + </div>
  31 +
  32 + <%= labelled_form_field(_("Username") + ":", text_field_tag(:login, @login)) %>
  33 + <%= labelled_form_field(_("Password") + ":", password_field_tag(:password)) %>
  34 + </div>
  35 +
  36 + <% button_bar do %>
  37 + <%= submit_button(:forward, _("Next")) %>
  38 + <% end %>
  39 + <p><%= _("We won't store your password or contact anyone without your permission.") %></p>
  40 +<% end %>
... ...
app/views/invite/invite_friends.rhtml 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +<% if profile.person? %>
  2 + <h1><%= _('Invite your friends') %></h1>
  3 +<% else %>
  4 + <h1><%= _('Invite your friends to join %s') % profile.name %></h1>
  5 +<% end %>
  6 +
  7 +<%= render :partial => 'invite/select_address_book' %>
  8 +
  9 +<% unless profile.person? %>
  10 + <h2><%= _('Invite others registered users') %></h2>
  11 + <p><%= _('You can also search for your friends\' profiles and invite them to join this community.') %></p>
  12 + <% form_tag :action => 'invite_registered_friend' do %>
  13 + <% search_action = url_for(:action => 'search_friend') %>
  14 + <%= token_input_field_tag(:q, 'search-friends', search_action,
  15 + { :hint_text => _('Type in a search for your friend'),
  16 + :focus => false }) %>
  17 +
  18 + <%= render :partial => 'invite/personalize_invitation_mail', :locals => {:mail_template => @mail_template } %>
  19 +
  20 + <% button_bar do %>
  21 + <%= submit_button('save', _('Invite'))%>
  22 + <%= button('cancel', _('Cancel'), profile.url)%>
  23 + <% end %>
  24 + <% end %>
  25 +<% end %>
  26 +
  27 +<div id="loadingScreen"></div>
... ...
app/views/invite/select_address_book.rhtml
... ... @@ -1,51 +0,0 @@
1   -<% if profile.person? %>
2   - <h1><%= _('Invite your friends') %></h1>
3   -<% else %>
4   - <h1><%= _('Invite your friends to join %s') % profile.name %></h1>
5   -<% end %>
6   -
7   -<h2><%= _('Step 1 of 2: Select address book') %></h2>
8   -
9   -<% form_tag do %>
10   -
11   - <%= [
12   - radio_button_tag(:import_from, "manual", @import_from == "manual", :onclick => 'hide_invite_friend_login_password()') + content_tag('label', _('Manually (empty field)'), :for => "import_from_manual"),
13   - radio_button_tag(:import_from, "gmail", @import_from == "gmail", :onclick => 'show_invite_friend_login_password(this.value)') + content_tag('label', 'Gmail', :for => 'import_from_gmail'),
14   - radio_button_tag(:import_from, "yahoo", @import_from == "yahoo", :onclick => 'show_invite_friend_login_password(this.value)') + content_tag('label', 'Yahoo', :for => "import_from_yahoo"),
15   - radio_button_tag(:import_from, "hotmail", @import_from == "hotmail", :onclick => 'show_invite_friend_login_password(this.value)') + content_tag('label', 'Hotmail', :for => "import_from_hotmail")
16   - ].join("\n<br/>\n") %>
17   -
18   - <script type="text/javascript">
19   - function hide_invite_friend_login_password() {
20   - $('invite-friends-login-password').hide();
21   - }
22   - function show_invite_friend_login_password(option) {
23   - if (option == 'hotmail') {
24   - $('hotmail_username_tip').show();
25   - } else {
26   - $('hotmail_username_tip').hide();
27   - }
28   - $('invite-friends-login-password').show();
29   - $('login').focus();
30   - }
31   - </script>
32   - <div id='invite-friends-login-password' <%= "style='display: none;'" if (@import_from == 'manual') %>>
33   - <div id='hotmail_username_tip'>
34   - <%= ui_icon('ui-icon-alert') %>
35   - <%= _('Please type your username in the format yourname@example.com') %>
36   - </div>
37   -
38   - <%= labelled_form_field(_("Username") + ":", text_field_tag(:login, @login)) %>
39   - <%= labelled_form_field(_("Password") + ":", password_field_tag(:password)) %>
40   - </div>
41   -
42   - <% button_bar do %>
43   - <%= submit_button(:forward, _("Next")) %>
44   - <% end %>
45   - <p><%= _("We won't store your password or contact anyone without your permission.") %></p>
46   -<% end %>
47   -
48   -<div id="loadingScreen"></div>
49   -
50   -
51   -
app/views/invite/select_friends.rhtml
... ... @@ -9,7 +9,7 @@
9 9  
10 10 <h2><%= _('Step 2 of 2: Selecting Friends') %></h2>
11 11  
12   -<%= button(:back, _('Back'), { :action => 'select_address_book' }, :id => 'invitation_back_button') %>
  12 +<%= button(:back, _('Back'), { :action => 'invite_friends' }, :id => 'invitation_back_button') %>
13 13  
14 14 <p>
15 15 <%= _('Indicate which friends you want to invite.') %>
... ... @@ -30,16 +30,7 @@
30 30 </div>
31 31 <% end -%>
32 32  
33   - <br/>
34   -
35   - <%= link_to_function(_('Personalize invitation mail'), nil) do |page|
36   - page['invitation-mail_template'].show
37   - end %>
38   -
39   - <div id='invitation-mail_template' style='display:none'>
40   - <%= h _("Now enter an invitation message. You must keep the <url> code in your invitation text. When your friends receive the invitation e-mail, <url> will be replaced by a link that they need to click to activate their account. <user> and <friend> codes will be replaced by your name and friend name, but they are optional.") %>
41   - <%= labelled_form_field(_('Invitation text:'), text_area_tag(:mail_template, @mail_template, :cols => 72, :rows => 8)) %>
42   - </div>
  33 + <%= render :partial => 'invite/personalize_invitation_mail', :locals => {:mail_template => @mail_template } %>
43 34  
44 35 <% button_bar do %>
45 36 <%= submit_button(:ok, _("Invite my friends!")) %>
... ...
app/views/profile/friends.rhtml
... ... @@ -18,7 +18,7 @@
18 18 <%= button :back, _('Go back'), { :controller => 'profile' } %>
19 19 <% if user == profile %>
20 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 => 'select_address_book') %>
  21 + <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'invite_friends') %>
22 22 <% end %>
23 23 <% end %>
24 24  
... ...
app/views/profile/members.rhtml
... ... @@ -18,7 +18,7 @@
18 18 <%= button :back, _('Go back'), { :controller => 'profile' } %>
19 19 <% if profile.community? and user %>
20 20 <% if user.has_permission?(:invite_members, profile) %>
21   - <%= button :search, _('Invite your friends to join %s') % profile.name, :controller => 'invite', :action => 'select_address_book' %>
  21 + <%= button :search, _('Invite your friends to join %s') % profile.name, :controller => 'invite', :action => 'invite_friends' %>
22 22 <% end %>
23 23 <% if user.has_permission?(:send_mail_to_members, profile) %>
24 24 <%= button :send, _('Send e-mail to members'), :controller => 'profile', :action => 'send_mail' %>
... ...
app/views/profile_members/_index_buttons.rhtml
... ... @@ -2,7 +2,7 @@
2 2 <%= button :back, _('Back'), :controller => 'profile_editor' %>
3 3 <%= button :add, _('Add members'), :action => 'add_members' if profile.enterprise? %>
4 4 <% if profile.community? and user.has_permission?(:invite_members, profile) %>
5   - <%= button :search, _('Invite your friends to join %s') % profile.short_name, :controller => 'invite', :action => 'select_address_book' %>
  5 + <%= button :search, _('Invite your friends to join %s') % profile.short_name, :controller => 'invite', :action => 'invite_friends' %>
6 6 <% end %>
7 7 <% if profile.community? and user.has_permission?(:send_mail_to_members, profile) %>
8 8 <%= button :send, _('Send e-mail to members'), :controller => 'profile', :action => 'send_mail' %>
... ...
config/routes.rb
... ... @@ -64,7 +64,7 @@ ActionController::Routing::Routes.draw do |map|
64 64 map.catalog 'catalog/:profile', :controller => 'catalog', :action => 'index', :profile => /#{Noosfero.identifier_format}/
65 65  
66 66 # invite
67   - map.invite 'profile/:profile/invite/friends', :controller => 'invite', :action => 'select_address_book', :profile => /#{Noosfero.identifier_format}/
  67 + map.invite 'profile/:profile/invite/friends', :controller => 'invite', :action => 'invite_friends', :profile => /#{Noosfero.identifier_format}/
68 68 map.invite 'profile/:profile/invite/:action', :controller => 'invite', :profile => /#{Noosfero.identifier_format}/
69 69  
70 70 # feeds per tag
... ...
plugins/stoa/lib/stoa_plugin.rb
... ... @@ -113,7 +113,7 @@ class StoaPlugin &lt; Noosfero::Plugin
113 113 { :title => _('Invite friends'),
114 114 :icon => 'invite-friends',
115 115 :url => {:controller => 'invite',
116   - :action => 'select_address_book'} } if context.send(:user) && context.send(:user).usp_id.present?
  116 + :action => 'invite_friends'} } if context.send(:user) && context.send(:user).usp_id.present?
117 117 end
118 118  
119 119 def remove_invite_friends_button
... ...
plugins/stoa/test/functional/invite_controller_test.rb
... ... @@ -20,7 +20,7 @@ class InviteControllerTest &lt; ActionController::TestCase
20 20 person_without_usp_id = User.create!(:login => 'user-without', :email => 'user-without@example.com', :password => 'test', :password_confirmation => 'test', :person_data => {:invitation_code => 12345678}).person
21 21  
22 22 login_as(person_without_usp_id.identifier)
23   - get :select_address_book, :profile => person_without_usp_id.identifier
  23 + get :invite_friends, :profile => person_without_usp_id.identifier
24 24 assert_response 403
25 25 get :select_friends, :profile => person_without_usp_id.identifier
26 26 assert_response 403
... ... @@ -30,7 +30,7 @@ class InviteControllerTest &lt; ActionController::TestCase
30 30 person_with_usp_id = User.create!(:login => 'user-with', :email => 'user-with@example.com', :password => 'test', :password_confirmation => 'test', :person_data => {:usp_id => 12345678}).person
31 31  
32 32 login_as(person_with_usp_id.identifier)
33   - get :select_address_book, :profile => person_with_usp_id.identifier
  33 + get :invite_friends, :profile => person_with_usp_id.identifier
34 34 assert_response 200
35 35 get :select_friends, :profile => person_with_usp_id.identifier, :contact_list => ContactList.create.id
36 36 assert_response 200
... ... @@ -42,7 +42,7 @@ class InviteControllerTest &lt; ActionController::TestCase
42 42 organization.add_admin(person_with_usp_id)
43 43  
44 44 login_as(person_with_usp_id.identifier)
45   - get :select_address_book, :profile => organization.identifier
  45 + get :invite_friends, :profile => organization.identifier
46 46 assert_response 200
47 47 get :select_friends, :profile => organization.identifier, :contact_list => ContactList.create.id
48 48 assert_response 200
... ...
test/functional/invite_controller_test.rb
... ... @@ -98,7 +98,7 @@ class InviteControllerTest &lt; ActionController::TestCase
98 98 end
99 99  
100 100 should 'display invitation page' do
101   - get :select_address_book, :profile => profile.identifier
  101 + get :invite_friends, :profile => profile.identifier
102 102 assert_response :success
103 103 assert_tag :tag => 'h1', :content => 'Invite your friends'
104 104 end
... ... @@ -117,8 +117,8 @@ class InviteControllerTest &lt; ActionController::TestCase
117 117 assert_equal InviteFriend.mail_template, assigns(:mail_template)
118 118 end
119 119  
120   - should 'deny select_address_book f user has no rights to invite members' do
121   - get :select_address_book, :profile => community.identifier
  120 + should 'deny invite_friends if user has no rights to invite members' do
  121 + get :invite_friends, :profile => community.identifier
122 122 assert_response 403 # forbidden
123 123 end
124 124  
... ... @@ -127,13 +127,13 @@ class InviteControllerTest &lt; ActionController::TestCase
127 127 assert_response 403 # forbidden
128 128 end
129 129  
130   - should 'deny select_address_book access when trying to invite friends to another user' do
131   - get :select_address_book, :profile => friend.identifier
  130 + should 'deny invite_friends access when trying to invite friends to another user' do
  131 + get :invite_friends, :profile => friend.identifier
132 132 assert_response 403 # forbidden
133 133 end
134 134  
135 135 should 'deny select_friends access when trying to invite friends to another user' do
136   - get :select_address_book, :profile => friend.identifier
  136 + get :select_friends, :profile => friend.identifier
137 137 assert_response 403 # forbidden
138 138 end
139 139  
... ... @@ -154,7 +154,7 @@ class InviteControllerTest &lt; ActionController::TestCase
154 154 community.add_admin(profile)
155 155 contact_list = ContactList.create
156 156 assert_difference Delayed::Job, :count, 1 do
157   - post :select_address_book, :profile => community.identifier, :contact_list => contact_list.id, :import_from => 'gmail'
  157 + post :invite_friends, :profile => community.identifier, :contact_list => contact_list.id, :import_from => 'gmail'
158 158 end
159 159 end
160 160  
... ... @@ -222,7 +222,7 @@ class InviteControllerTest &lt; ActionController::TestCase
222 222 assert_difference ContactList, :count, -1 do
223 223 get :cancel_fetching_emails, :profile => profile.identifier, :contact_list => contact_list.id
224 224 end
225   - assert_redirected_to :action => 'select_address_book'
  225 + assert_redirected_to :action => 'invite_friends'
226 226 end
227 227  
228 228 should 'set locale in the background job' do
... ... @@ -233,6 +233,41 @@ class InviteControllerTest &lt; ActionController::TestCase
233 233 assert_equal 'pt', Delayed::Job.first.payload_object.locale
234 234 end
235 235  
  236 + should 'search friends profiles by name, email or identifier' do
  237 + friend1 = create_user('willy').person
  238 + friend2 = create_user('william').person
  239 + friend1.name = 'cris'
  240 + friend2.email = 'me@example.com'
  241 + friend1.save
  242 + friend2.save
  243 +
  244 + get :search_friend, :profile => profile.identifier, :q => 'me@'
  245 +
  246 + assert_equal 'text/html', @response.content_type
  247 + assert_equal [{"name" => friend2.name, "id" => friend2.id}].to_json, @response.body
  248 +
  249 + get :search_friend, :profile => profile.identifier, :q => 'cri'
  250 +
  251 + assert_equal [{"name" => friend1.name, "id" => friend1.id}].to_json, @response.body
  252 +
  253 + get :search_friend, :profile => profile.identifier, :q => 'will'
  254 +
  255 + assert_equal [{"name" => friend1.name, "id" => friend1.id}, {"name" => friend2.name, "id" => friend2.id}].to_json, @response.body
  256 + end
  257 +
  258 + should 'invite registered users through profile id' do
  259 + friend1 = create_user('testuser1').person
  260 + friend2 = create_user('testuser2').person
  261 + assert_difference Delayed::Job, :count, 1 do
  262 + post :invite_registered_friend, :profile => profile.identifier, :q => "#{friend1.id},#{friend2.id}", :mail_template => "click: <url>"
  263 + assert_redirected_to :controller => 'profile', :action => 'friends'
  264 + end
  265 +
  266 + assert_difference InviteFriend, :count, 2 do
  267 + process_delayed_job_queue
  268 + end
  269 + end
  270 +
236 271 private
237 272  
238 273 def json_response
... ...
test/integration/routing_test.rb
... ... @@ -213,7 +213,7 @@ class RoutingTest &lt; ActionController::IntegrationTest
213 213 end
214 214  
215 215 def test_invite_routing
216   - assert_routing('/profile/colivre/invite/friends', :controller => 'invite', :action => 'select_address_book', :profile => 'colivre')
  216 + assert_routing('/profile/colivre/invite/friends', :controller => 'invite', :action => 'invite_friends', :profile => 'colivre')
217 217 end
218 218  
219 219 def test_chat_routing
... ...