Commit ca285e1e979f3d756eee29a315ddfb6ef36bcb30

Authored by Daniela Feitosa
Committed by Antonio Terceiro
1 parent f9cb2dd4

fetching emails for invitation done in background

* Added message if user wants to fetch from hotmail
  * Added <url> to message if user removed it
  * Refactored invite_controller
  * Added ContactList
  * Added get_email_contacts_job
  * Added invitation_job

    (ActionItem1640)
app/controllers/public/invite_controller.rb
@@ -2,42 +2,57 @@ class InviteController &lt; PublicController @@ -2,42 +2,57 @@ class InviteController &lt; PublicController
2 2
3 needs_profile 3 needs_profile
4 before_filter :login_required 4 before_filter :login_required
5 - before_filter :check_permissions_to_invite, :only => 'friends' 5 + before_filter :check_permissions_to_invite
6 6
7 - def friends  
8 - step = params[:step] 7 + def select_address_book
  8 + @import_from = params[:import_from] || "manual"
9 if request.post? 9 if request.post?
10 - if step == '1'  
11 - begin  
12 - @contacts = Invitation.get_contacts(params[:import_from], params[:login], params[:password])  
13 - rescue  
14 - @login = params[:login]  
15 - flash.now[:notice] = _('There was an error while looking for your contact list. Did you enter correct login and password?')  
16 - end  
17 - elsif step == '2'  
18 - manual_import_addresses = params[:manual_import_addresses]  
19 - webmail_import_addresses = params[:webmail_import_addresses]  
20 - contacts_to_invite = Invitation.join_contacts(manual_import_addresses, webmail_import_addresses)  
21 - if !params[:mail_template].match(/<url>/)  
22 - flash.now[:notice] = _('&lt;url&gt; is needed in invitation mail.')  
23 - elsif !contacts_to_invite.empty?  
24 - Delayed::Job.enqueue InvitationJob.new(user.id, contacts_to_invite, params[:mail_template], profile.id)  
25 - session[:notice] = _('Your invitations are being sent.')  
26 - if profile.person?  
27 - redirect_to :controller => 'friends'  
28 - else  
29 - redirect_to :controller => 'profile_members'  
30 - end 10 + contact_list = ContactList.create
  11 + Delayed::Job.enqueue GetEmailContactsJob.new(@import_from, params[:login], params[:password], contact_list.id) if @import_from != 'manual'
  12 + redirect_to :action => 'select_friends', :contact_list => contact_list.id, :import_from => @import_from
  13 + end
  14 + end
  15 +
  16 + def select_friends
  17 + @contact_list = ContactList.find(params[:contact_list])
  18 + @mail_template = params[:mail_template] || environment.invitation_mail_template(profile)
  19 + @import_from = params[:import_from] || "manual"
  20 + if request.post?
  21 + manual_import_addresses = params[:manual_import_addresses]
  22 + webmail_import_addresses = params[:webmail_import_addresses]
  23 + contacts_to_invite = Invitation.join_contacts(manual_import_addresses, webmail_import_addresses)
  24 + if !contacts_to_invite.empty?
  25 + Delayed::Job.enqueue InvitationJob.new(current_user.person.id, contacts_to_invite, params[:mail_template], profile.id, @contact_list.id)
  26 + session[:notice] = _('Your invitations are being sent.')
  27 + if profile.person?
  28 + redirect_to :controller => 'profile', :action => 'friends'
31 else 29 else
32 - flash.now[:notice] = _('Please enter a valid email address.') 30 + redirect_to :controller => 'profile', :action => 'members'
33 end 31 end
34 - @contacts = params[:webmail_friends] ? params[:webmail_friends].map {|e| YAML.load(e)} : []  
35 - @manual_import_addresses = manual_import_addresses || ""  
36 - @webmail_import_addresses = webmail_import_addresses || [] 32 + return
  33 + else
  34 + session[:notice] = _('Please enter a valid email address.')
37 end 35 end
  36 + @manual_import_addresses = manual_import_addresses || ""
  37 + @webmail_import_addresses = webmail_import_addresses || []
38 end 38 end
39 - @import_from = params[:import_from] || "manual"  
40 - @mail_template = params[:mail_template] || environment.invitation_mail_template(profile) 39 + end
  40 +
  41 + def invitation_data
  42 + contact_list = ContactList.find(params[:contact_list])
  43 + render :text => contact_list.data.to_json, :layout => false, :content_type => "application/javascript"
  44 + end
  45 +
  46 + def add_contact_list
  47 + contact_list = ContactList.find(params[:contact_list])
  48 + contacts = contact_list.list
  49 + render :partial => 'invite/contact_list', :locals => {:contacts => contacts}
  50 + end
  51 +
  52 + def cancel_fetching_emails
  53 + contact_list = ContactList.find(params[:contact_list])
  54 + contact_list.destroy
  55 + redirect_to :action => 'select_address_book'
41 end 56 end
42 57
43 protected 58 protected
app/models/contact_list.rb 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +class ContactList < ActiveRecord::Base
  2 +
  3 + serialize :list, Array
  4 +
  5 + def list
  6 + self[:list] || []
  7 + end
  8 +
  9 + def data
  10 + if self.fetched
  11 + { "fetched" => true, "contact_list" => self.id, "error" => self.error_fetching }
  12 + else
  13 + {}
  14 + end
  15 + end
  16 +
  17 + def register_auth_error
  18 + msg = _('There was an error while authenticating. Did you enter correct login and password?')
  19 + self.update_attributes(:fetched => true, :error_fetching => msg)
  20 + end
  21 +
  22 + def register_error
  23 + msg = _('There was an error while looking for your contact list. Please, try again')
  24 + self.update_attributes(:fetched => true, :error_fetching => msg)
  25 + end
  26 +
  27 +end
app/models/invitation.rb
@@ -11,7 +11,6 @@ class Invitation &lt; Task @@ -11,7 +11,6 @@ class Invitation &lt; Task
11 validates_format_of :friend_email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => Proc.new{|invite| invite.target_id.blank?} 11 validates_format_of :friend_email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => Proc.new{|invite| invite.target_id.blank?}
12 12
13 validates_presence_of :message, :if => Proc.new{|invite| invite.target_id.blank?} 13 validates_presence_of :message, :if => Proc.new{|invite| invite.target_id.blank?}
14 - validates_format_of :message, :with => /<url>/, :if => Proc.new{|invite| invite.target_id.blank?}  
15 14
16 alias :person :requestor 15 alias :person :requestor
17 alias :person= :requestor= 16 alias :person= :requestor=
@@ -19,6 +18,12 @@ class Invitation &lt; Task @@ -19,6 +18,12 @@ class Invitation &lt; Task
19 alias :friend :target 18 alias :friend :target
20 alias :friend= :target= 19 alias :friend= :target=
21 20
  21 + before_create do |task|
  22 + if task.message && !task.message.match(/<url>/)
  23 + task.message += task.message_to_accept_invitation
  24 + end
  25 + end
  26 +
22 after_create do |task| 27 after_create do |task|
23 TaskMailer.deliver_invitation_notification(task) unless task.friend 28 TaskMailer.deliver_invitation_notification(task) unless task.friend
24 end 29 end
@@ -72,21 +77,26 @@ class Invitation &lt; Task @@ -72,21 +77,26 @@ class Invitation &lt; Task
72 end 77 end
73 end 78 end
74 79
75 - def self.get_contacts(source, login, password)  
76 - contacts = [] 80 + def self.get_contacts(source, login, password, contact_list_id)
  81 + contact_list = ContactList.find(contact_list_id)
77 case source 82 case source
78 when "gmail" 83 when "gmail"
79 - contacts = Contacts::Gmail.new(login, password).contacts 84 + email_service = Contacts::Gmail.new(login, password)
80 when "yahoo" 85 when "yahoo"
81 - contacts = Contacts::Yahoo.new(login, password).contacts 86 + email_service = Contacts::Yahoo.new(login, password)
82 when "hotmail" 87 when "hotmail"
83 - contacts = Contacts::Hotmail.new(login, password).contacts 88 + email_service = Contacts::Hotmail.new(login, password)
84 when "manual" 89 when "manual"
85 #do nothing 90 #do nothing
86 else 91 else
87 raise NotImplementedError, 'Unknown source to get contacts' 92 raise NotImplementedError, 'Unknown source to get contacts'
88 end 93 end
89 - contacts.map { |contact| contact + ["#{contact[0]} <#{contact[1]}>"] } 94 + if email_service
  95 + contact_list.list = email_service.contacts.map { |contact| contact + ["#{contact[0]} <#{contact[1]}>"] }
  96 + contact_list.fetched = true
  97 + contact_list.save
  98 + end
  99 + contact_list.list
90 end 100 end
91 101
92 def self.join_contacts(manual_import_addresses, webmail_import_addresses) 102 def self.join_contacts(manual_import_addresses, webmail_import_addresses)
@@ -112,4 +122,7 @@ class Invitation &lt; Task @@ -112,4 +122,7 @@ class Invitation &lt; Task
112 raise 'You should implement mail_template in a subclass' 122 raise 'You should implement mail_template in a subclass'
113 end 123 end
114 124
  125 + def message_to_accept_invitation
  126 + '<p>' + _('To accept invitation, please follow this link: <url>') + '</p>'
  127 + end
115 end 128 end
app/views/friends/index.rhtml
@@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
14 <% button_bar do %> 14 <% button_bar do %>
15 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> 15 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>
16 <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %> 16 <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %>
17 - <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'friends') %> 17 + <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'select_address_book') %>
18 <% end %> 18 <% end %>
19 <% end %> 19 <% end %>
20 20
@@ -40,11 +40,11 @@ @@ -40,11 +40,11 @@
40 <%= pagination_links @friends, :param_name => 'npage' %> 40 <%= pagination_links @friends, :param_name => 'npage' %>
41 </div> 41 </div>
42 42
43 -<% button_bar do %>  
44 - <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>  
45 - <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %>  
46 - <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'friends') %>  
47 -<% end %> 43 + <% button_bar do %>
  44 + <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>
  45 + <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %>
  46 + <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'select_address_book') %>
  47 + <% end %>
48 <% end %> 48 <% end %>
49 49
50 </div><!-- end id="manage_friends" --> 50 </div><!-- end id="manage_friends" -->
app/views/invite/_contact_list.rhtml 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +<% friend_pos = 0 %>
  2 +<% contacts.each do |contact| %>
  3 + <% friend_pos += 1 %>
  4 + <p>
  5 + <%= check_box_tag("webmail_import_addresses[]", contact[2],
  6 + (!@webmail_import_addresses || @webmail_import_addresses.include?(contact[2])),
  7 + :id => "contacts_to_invite_#{friend_pos}",
  8 + :class => "contact_to_invite" )
  9 + %>
  10 + <label for="<%= "contacts_to_invite_#{friend_pos}" %>"><%= "#{contact[0]} (#{contact[1]})" %></label>
  11 + </p>
  12 +<% end %>
app/views/invite/_dialog_wait_loading.rhtml 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  1 +<% javascript_tag do %>
  2 + jQuery(function($) {
  3 + $("#loading-dialog").dialog({
  4 + height: 160,
  5 + width: 450,
  6 + modal: true,
  7 + resizable: false,
  8 + title: "<%= ui_icon('ui-icon-info') + _('Please, wait...') %>",
  9 + open: check_contact_list('<%= contact_list.to_s %>'),
  10 + });
  11 + });
  12 +<% end %>
  13 +
  14 +
  15 +<div id="loading-dialog">
  16 + <p><%= _('Your e-mails contacts are being fetched') %></p>
  17 + <p><%= _('If it takes too long, you will be redirected to the previous page to try again. Be sure to fill in the fields with your correct login and password.') %>
  18 + <span class='loading-message'/>
  19 + <%= link_to(_('Verify contact list'), {:action => 'invitation_data', :contact_list => @contact_list}, :id => "verify-contact-list", :style => 'display:none') %>
  20 + <%= link_to(_('Add contact list'), {:action => 'add_contact_list', :contact_list => @contact_list}, :id => "add-contact-list", :style => 'display:none') %>
  21 + <%= link_to(_('Cancel fetching e-mails'), {:action => 'cancel_fetching_emails', :contact_list => @contact_list}, :id => "cancel-fetching-emails", :style => 'display:none') %>
  22 +</div>
  23 +
app/views/invite/friends.rhtml
@@ -1,93 +0,0 @@ @@ -1,93 +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 -<% unless @contacts %>  
8 -  
9 - <h2><%= _('Step 1 of 2: Select address book') %></h2>  
10 -  
11 - <% form_tag do %>  
12 - <%= hidden_field_tag(:step, 1) %>  
13 -  
14 - <%= [  
15 - 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"),  
16 - radio_button_tag(:import_from, "gmail", @import_from == "gmail", :onclick => 'show_invite_friend_login_password()') + content_tag('label', 'Gmail', :for => 'import_from_gmail'),  
17 - radio_button_tag(:import_from, "yahoo", @import_from == "yahoo", :onclick => 'show_invite_friend_login_password()') + content_tag('label', 'Yahoo', :for => "import_from_yahoo"),  
18 - radio_button_tag(:import_from, "hotmail", @import_from == "hotmail", :onclick => 'show_invite_friend_login_password()') + content_tag('label', 'Hotmail', :for => "import_from_hotmail")  
19 - ].join("\n<br/>\n") %>  
20 -  
21 - <script type="text/javascript">  
22 - function hide_invite_friend_login_password() {  
23 - $('invite-friends-login-password').hide();  
24 - }  
25 - function show_invite_friend_login_password() {  
26 - $('invite-friends-login-password').show();  
27 - $('login').focus();  
28 - }  
29 - </script>  
30 - <div id='invite-friends-login-password' <%= "style='display: none;'" if (@import_from == 'manual') %>>  
31 - <%= labelled_form_field(_("Username") + ":", text_field_tag(:login, @login)) %>  
32 - <%= labelled_form_field(_("Password") + ":", password_field_tag(:password)) %>  
33 - </div>  
34 -  
35 - <% button_bar do %>  
36 - <%= submit_button(:forward, _("Next")) %>  
37 - <% end %>  
38 - <p><%= _("We won't store your password or contact anyone without your permission.") %></p>  
39 - <% end %>  
40 -  
41 -<% else %>  
42 -  
43 - <h2><%= _('Step 2 of 2: Selecting Friends') %></h2>  
44 - <p>  
45 - <%= _('Indicate which friends you want to invite.') %>  
46 - </p>  
47 -  
48 - <% form_tag do %>  
49 - <%= hidden_field_tag(:step, 2) %>  
50 - <%= hidden_field_tag(:import_from, @import_from) %>  
51 -  
52 - <div>  
53 - <%= labelled_form_field(_('Enter one e-mail address per line:'), text_area_tag(:manual_import_addresses, (@manual_import_addresses || ''), :cols => 72, :rows => 5)) %>  
54 - </div>  
55 - <% if @import_from != 'manual' %>  
56 - <div>  
57 - <%= link_to_function _('Check all'), "$$('input.contact_to_invite').each(function(checkbox) { checkbox.checked = true; });" %>  
58 - <%= link_to_function _('Uncheck all'), "$$('input.contact_to_invite').each(function(checkbox) { checkbox.checked = false; });" %>  
59 - <% friend_pos = 0 %>  
60 - <div id='contacts-list'>  
61 - <% @contacts.each do |contact| %>  
62 - <% friend_pos += 1 %>  
63 - <p>  
64 - <%= hidden_field_tag("webmail_friends[]", contact.to_yaml) %>  
65 - <%= check_box_tag("webmail_import_addresses[]", contact[2],  
66 - (!@webmail_import_addresses || @webmail_import_addresses.include?(contact[2])),  
67 - :id => "contacts_to_invite_#{friend_pos}",  
68 - :class => "contact_to_invite" )  
69 - %>  
70 - <label for="<%= "contacts_to_invite_#{friend_pos}" %>"><%= "#{contact[0]} (#{contact[1]})" %></label>  
71 - </p>  
72 - <% end %>  
73 - </div>  
74 - </div>  
75 - <% end -%>  
76 -  
77 - <br/>  
78 -  
79 - <%= link_to_function(_('Personalize invitation mail'), nil) do |page|  
80 - page['invitation-mail_template'].show  
81 - end %>  
82 -  
83 - <div id='invitation-mail_template' style='display:none'>  
84 - <%= 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.") %>  
85 - <%= labelled_form_field(_('Invitation text:'), text_area_tag(:mail_template, @mail_template, :cols => 72, :rows => 8)) %>  
86 - </div>  
87 -  
88 - <% button_bar do %>  
89 - <%= submit_button(:ok, _("Invite my friends!")) %>  
90 - <% end %>  
91 - <% end %>  
92 -  
93 -<% end %>  
app/views/invite/select_address_book.rhtml 0 → 100644
@@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
  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 0 → 100644
@@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
  1 +<%= render :partial => 'invite/dialog_wait_loading', :locals => {:contact_list => @contact_list.id } if @import_from != 'manual' %>
  2 +
  3 +<% if profile.person? %>
  4 + <h1><%= _('Invite your friends') %></h1>
  5 +<% else %>
  6 + <h1><%= _('Invite your friends to join %s') % profile.name %></h1>
  7 +<% end %>
  8 +
  9 +
  10 +<h2><%= _('Step 2 of 2: Selecting Friends') %></h2>
  11 +
  12 +<%= button(:back, _('Back'), { :action => 'select_address_book' }, :id => 'invitation_back_button') %>
  13 +
  14 +<p>
  15 +<%= _('Indicate which friends you want to invite.') %>
  16 +</p>
  17 +
  18 +<% form_tag do %>
  19 + <%= hidden_field_tag(:import_from, @import_from) %>
  20 + <%= hidden_field_tag(:contact_list, @contact_list.id) %>
  21 +
  22 + <div>
  23 + <%= labelled_form_field(_('Enter one e-mail address per line:'), text_area_tag(:manual_import_addresses, (@manual_import_addresses || ''), :cols => 72, :rows => 5)) %>
  24 + </div>
  25 + <% if @import_from != 'manual' %>
  26 + <div>
  27 + <%= link_to_function _('Check all'), "$$('input.contact_to_invite').each(function(checkbox) { checkbox.checked = true; });" %>
  28 + <%= link_to_function _('Uncheck all'), "$$('input.contact_to_invite').each(function(checkbox) { checkbox.checked = false; });" %>
  29 + <div id='contacts-list'></div>
  30 + </div>
  31 + <% end -%>
  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>
  43 +
  44 + <% button_bar do %>
  45 + <%= submit_button(:ok, _("Invite my friends!")) %>
  46 + <% end %>
  47 +<% end %>
app/views/profile/friends.rhtml
@@ -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 => 'friends') %> 21 + <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'select_address_book') %>
22 <% end %> 22 <% end %>
23 <% end %> 23 <% end %>
24 24
app/views/profile/members.rhtml
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 <% button_bar do %> 17 <% button_bar do %>
18 <%= button :back, _('Go back'), { :controller => 'profile' } %> 18 <%= button :back, _('Go back'), { :controller => 'profile' } %>
19 <% if profile.community? and user and user.has_permission?(:invite_members, profile) %> 19 <% if profile.community? and user and user.has_permission?(:invite_members, profile) %>
20 - <%= button :search, _('Invite your friends to join %s') % profile.name, :controller => 'invite', :action => 'friends' %> 20 + <%= button :search, _('Invite your friends to join %s') % profile.name, :controller => 'invite', :action => 'selects_address_book' %>
21 <% end %> 21 <% end %>
22 <% end %> 22 <% end %>
23 23
app/views/profile_members/index.rhtml
@@ -6,6 +6,6 @@ @@ -6,6 +6,6 @@
6 <%= button :back, _('Back'), :controller => 'profile_editor' %> 6 <%= button :back, _('Back'), :controller => 'profile_editor' %>
7 <%= button :add, _('Add members'), :action => 'add_members' if profile.enterprise? %> 7 <%= button :add, _('Add members'), :action => 'add_members' if profile.enterprise? %>
8 <% if profile.community? and user.has_permission?(:invite_members, profile) %> 8 <% if profile.community? and user.has_permission?(:invite_members, profile) %>
9 - <%= button :search, _('Invite your friends to join %s') % profile.name, :controller => 'invite', :action => 'friends' %> 9 + <%= button :search, _('Invite your friends to join %s') % profile.name, :controller => 'invite', :action => 'select_address_book' %>
10 <% end %> 10 <% end %>
11 <% end %> 11 <% end %>
config/initializers/delayed_job_config.rb 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +Delayed::Worker.max_attempts = 2
  2 +Delayed::Worker.max_run_time = 10.minutes
db/migrate/20100823190348_create_contact_lists.rb 0 → 100644
@@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
  1 +class CreateContactLists < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :contact_lists do |t|
  4 + t.text :list
  5 + t.string :error_fetching
  6 + t.boolean :fetched, :default => false
  7 + t.timestamps
  8 + end
  9 + end
  10 +
  11 + def self.down
  12 + drop_table :contact_lists
  13 + end
  14 +end
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 # 9 #
10 # It's strongly recommended to check this file into your version control system. 10 # It's strongly recommended to check this file into your version control system.
11 11
12 -ActiveRecord::Schema.define(:version => 20100822034415) do 12 +ActiveRecord::Schema.define(:version => 20100823190348) do
13 13
14 create_table "article_versions", :force => true do |t| 14 create_table "article_versions", :force => true do |t|
15 t.integer "article_id" 15 t.integer "article_id"
@@ -145,9 +145,9 @@ ActiveRecord::Schema.define(:version =&gt; 20100822034415) do @@ -145,9 +145,9 @@ ActiveRecord::Schema.define(:version =&gt; 20100822034415) do
145 t.string "name", :null => false 145 t.string "name", :null => false
146 t.string "description" 146 t.string "description"
147 t.string "link" 147 t.string "link"
  148 + t.integer "environment_id"
148 t.datetime "created_at" 149 t.datetime "created_at"
149 t.datetime "updated_at" 150 t.datetime "updated_at"
150 - t.integer "environment_id"  
151 end 151 end
152 152
153 create_table "comments", :force => true do |t| 153 create_table "comments", :force => true do |t|
@@ -160,6 +160,14 @@ ActiveRecord::Schema.define(:version =&gt; 20100822034415) do @@ -160,6 +160,14 @@ ActiveRecord::Schema.define(:version =&gt; 20100822034415) do
160 t.datetime "created_at" 160 t.datetime "created_at"
161 end 161 end
162 162
  163 + create_table "contact_lists", :force => true do |t|
  164 + t.text "list"
  165 + t.string "error_fetching"
  166 + t.boolean "fetched", :default => false
  167 + t.datetime "created_at"
  168 + t.datetime "updated_at"
  169 + end
  170 +
163 create_table "delayed_jobs", :force => true do |t| 171 create_table "delayed_jobs", :force => true do |t|
164 t.integer "priority", :default => 0 172 t.integer "priority", :default => 0
165 t.integer "attempts", :default => 0 173 t.integer "attempts", :default => 0
@@ -351,9 +359,9 @@ ActiveRecord::Schema.define(:version =&gt; 20100822034415) do @@ -351,9 +359,9 @@ ActiveRecord::Schema.define(:version =&gt; 20100822034415) do
351 359
352 create_table "roles", :force => true do |t| 360 create_table "roles", :force => true do |t|
353 t.string "name" 361 t.string "name"
  362 + t.text "permissions"
354 t.string "key" 363 t.string "key"
355 t.boolean "system", :default => false 364 t.boolean "system", :default => false
356 - t.text "permissions"  
357 t.integer "environment_id" 365 t.integer "environment_id"
358 end 366 end
359 367
features/invitation.feature
@@ -32,15 +32,14 @@ Feature: invitation @@ -32,15 +32,14 @@ Feature: invitation
32 When I am on /profile/josesilva/invite/friends 32 When I am on /profile/josesilva/invite/friends
33 Then I should see "Invite your friends" 33 Then I should see "Invite your friends"
34 34
35 - # why not work?  
36 - Scenario: back to manage friends after invite friends 35 + Scenario: back to friends after invite friends
37 Given I am on /myprofile/josesilva/friends 36 Given I am on /myprofile/josesilva/friends
38 And I follow "Invite people from my e-mail contacts" 37 And I follow "Invite people from my e-mail contacts"
39 And I press "Next" 38 And I press "Next"
40 And I fill in "manual_import_addresses" with "misfits@devil.doll" 39 And I fill in "manual_import_addresses" with "misfits@devil.doll"
41 And I fill in "mail_template" with "Follow this link <url>" 40 And I fill in "mail_template" with "Follow this link <url>"
42 When I press "Invite my friends!" 41 When I press "Invite my friends!"
43 - Then I should be on /myprofile/josesilva/friends 42 + Then I should be on /profile/josesilva/friends
44 43
45 Scenario: see link to invite members to community 44 Scenario: see link to invite members to community
46 When I am on /profile/26-bsslines/members 45 When I am on /profile/26-bsslines/members
@@ -75,14 +74,14 @@ Feature: invitation @@ -75,14 +74,14 @@ Feature: invitation
75 Given I am on Beatles For Sale's members management 74 Given I am on Beatles For Sale's members management
76 Then I should not see "Invite your friends to join Beatles For Sale" link 75 Then I should not see "Invite your friends to join Beatles For Sale" link
77 76
78 - Scenario: back to manage members after invite friends 77 + Scenario: back to members after invite friends to join a community
79 Given I am on 26 Bsslines's members management 78 Given I am on 26 Bsslines's members management
80 And I follow "Invite your friends to join 26 Bsslines" 79 And I follow "Invite your friends to join 26 Bsslines"
81 And I press "Next" 80 And I press "Next"
82 And I fill in "manual_import_addresses" with "misfits@devil.doll" 81 And I fill in "manual_import_addresses" with "misfits@devil.doll"
83 And I fill in "mail_template" with "Follow this link <url>" 82 And I fill in "mail_template" with "Follow this link <url>"
84 When I press "Invite my friends!" 83 When I press "Invite my friends!"
85 - Then I should be on /myprofile/26-bsslines/profile_members 84 + Then I should be on /profile/26-bsslines/members
86 85
87 Scenario: noosfero user receives a task when a user invites to join a community 86 Scenario: noosfero user receives a task when a user invites to join a community
88 Given I am on 26 Bsslines's members management 87 Given I am on 26 Bsslines's members management
lib/get_email_contacts_job.rb 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +class GetEmailContactsJob < Struct.new(:import_from, :login, :password, :contact_list_id)
  2 + def perform
  3 + begin
  4 + Invitation.get_contacts(import_from, login, password, contact_list_id)
  5 + rescue Contacts::AuthenticationError => ex
  6 + ContactList.find(contact_list_id).register_auth_error
  7 + rescue Exception => ex
  8 + ContactList.find(contact_list_id).register_error
  9 + end
  10 + end
  11 +end
lib/invitation_job.rb
1 -class InvitationJob < Struct.new(:person_id, :contacts_to_invite, :message, :profile_id) 1 +class InvitationJob < Struct.new(:person_id, :contacts_to_invite, :message, :profile_id, :contact_list_id)
2 def perform 2 def perform
3 begin 3 begin
4 - person = Person.find(person_id)  
5 - profile = Profile.find(profile_id)  
6 - Invitation.invite(person, contacts_to_invite, message, profile) 4 + person = Person.find(person_id)
  5 + profile = Profile.find(profile_id)
  6 + Invitation.invite(person, contacts_to_invite, message, profile)
  7 + ContactList.find(contact_list_id).destroy
7 rescue ActiveRecord::NotFound => e 8 rescue ActiveRecord::NotFound => e
8 - # ... 9 + #...
9 end 10 end
10 end 11 end
11 end 12 end
public/javascripts/application.js
@@ -455,9 +455,46 @@ jQuery(function($) { @@ -455,9 +455,46 @@ jQuery(function($) {
455 $('#user .not-logged-in, .login-block .not-logged-user').fadeIn(); 455 $('#user .not-logged-in, .login-block .not-logged-user').fadeIn();
456 } 456 }
457 if (data.notice) { 457 if (data.notice) {
458 - var $noticeBox = $('<div id="notice"></div>').html(data.notice).appendTo('body').fadeTo('fast', 0.8);  
459 - $noticeBox.click(function() { $(this).hide(); });  
460 - setTimeout(function() { $noticeBox.fadeOut('fast'); }, 5000); 458 + display_notice(data.notice);
461 } 459 }
462 }); 460 });
463 }); 461 });
  462 +
  463 +// controls the display of contact list
  464 +function check_contact_list(contact_list) {
  465 + jQuery(function($) {
  466 + var verify_url = $('#verify-contact-list').attr('href');
  467 + var add_contacts_url = $('#add-contact-list').attr('href');
  468 + var cancel_contacts_fetching_url = $('#cancel-fetching-emails').attr('href');
  469 + var interval = setInterval(function() {
  470 + $.getJSON(verify_url, function(data) {
  471 + if (data.fetched) {
  472 + clearInterval(interval);
  473 + if (data.error) {
  474 + $("#loading-dialog").dialog('close');
  475 + $.get(cancel_contacts_fetching_url);
  476 + redirect_to($('#invitation_back_button').attr('href'));
  477 + display_notice(data.error);
  478 + } else {
  479 + $.get(add_contacts_url, function(data){
  480 + $("#contacts-list").html(data);
  481 + });
  482 + };
  483 + $("#loading-dialog").dialog('close');
  484 + }
  485 + });
  486 + }, 5000);
  487 + setTimeout(function() {
  488 + clearInterval(interval);
  489 + $("#loading-dialog").dialog('close');
  490 + $.get(cancel_contacts_fetching_url);
  491 + redirect_to($('#invitation_back_button').attr('href'));
  492 + }, 600000);
  493 + });
  494 +}
  495 +
  496 +function display_notice(message) {
  497 + var $noticeBox = jQuery('<div id="notice"></div>').html(message).appendTo('body').fadeTo('fast', 0.8);
  498 + $noticeBox.click(function() { $(this).hide(); });
  499 + setTimeout(function() { $noticeBox.fadeOut('fast'); }, 5000);
  500 +}
public/stylesheets/application.css
@@ -3189,6 +3189,26 @@ h1#agenda-title { @@ -3189,6 +3189,26 @@ h1#agenda-title {
3189 margin: 5px 0px; 3189 margin: 5px 0px;
3190 } 3190 }
3191 3191
  3192 +#loading-dialog .loading-message {
  3193 + height: 32px;
  3194 + width: 32px;
  3195 + left: 209px;
  3196 + bottom: 5px;
  3197 + position: absolute;
  3198 + display: block;
  3199 + background: transparent url(/images/loading-dark.gif) center center no-repeat;
  3200 +}
  3201 +
  3202 +/* hide the close x on the loading screen */
  3203 +.controller-invite .ui-dialog-titlebar-close {
  3204 + display: none;
  3205 +}
  3206 +
  3207 +#hotmail_username_tip {
  3208 + color: red;
  3209 + margin-top: 10px;
  3210 +}
  3211 +
3192 /* ==> public/stylesheets/controller_manage_products.css <== */ 3212 /* ==> public/stylesheets/controller_manage_products.css <== */
3193 3213
3194 #category_form { 3214 #category_form {
script/delayed_job
@@ -6,28 +6,9 @@ @@ -6,28 +6,9 @@
6 # The role of this script is to just start/stop the daemon, write a PID file, 6 # The role of this script is to just start/stop the daemon, write a PID file,
7 # etc. The actual feed update logic is DelayedJob plugin. 7 # etc. The actual feed update logic is DelayedJob plugin.
8 8
  9 +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
9 require 'daemons' 10 require 'daemons'
  11 +require 'delayed/command'
10 12
11 -NOOSFERO_ROOT = File.expand_path(File.dirname(__FILE__) + '/../')  
12 -  
13 -options = {  
14 - :dir_mode => :normal,  
15 - :dir => File.dirname(__FILE__) + '/../tmp/pids',  
16 - :multiple => false,  
17 - :backtrace => true,  
18 - :monitor => true,  
19 -}  
20 -  
21 -Daemons.run_proc('job_runner', options) do  
22 - if ARGV.include?('--')  
23 - ARGV.slice! 0..ARGV.index('--')  
24 - else  
25 - ARGV.clear  
26 - end  
27 -  
28 - Dir.chdir NOOSFERO_ROOT  
29 - RAILS_ENV = ARGV.first || ENV['RAILS_ENV'] || 'development'  
30 - require NOOSFERO_ROOT + '/config/environment'  
31 -  
32 - Delayed::Worker.new.start  
33 -end 13 +ENV['RAILS_ENV'] ||= "production"
  14 +Delayed::Command.new(ARGV).daemonize
script/production
@@ -20,14 +20,14 @@ do_start() { @@ -20,14 +20,14 @@ do_start() {
20 clear_cache 20 clear_cache
21 ./script/ferret_server -e $RAILS_ENV start 21 ./script/ferret_server -e $RAILS_ENV start
22 ./script/feed-updater start 22 ./script/feed-updater start
23 - ./script/delayed_job start 23 +# ./script/delayed_job start -n 4
24 mongrel_rails cluster::start 24 mongrel_rails cluster::start
25 } 25 }
26 26
27 do_stop() { 27 do_stop() {
28 mongrel_rails cluster::stop 28 mongrel_rails cluster::stop
29 ./script/delayed_job stop 29 ./script/delayed_job stop
30 - ./script/feed-updater stop 30 +# ./script/feed-updater stop
31 ./script/ferret_server -e $RAILS_ENV stop 31 ./script/ferret_server -e $RAILS_ENV stop
32 } 32 }
33 33
test/functional/invite_controller_test.rb
@@ -11,9 +11,10 @@ class InviteControllerTest &lt; ActionController::TestCase @@ -11,9 +11,10 @@ class InviteControllerTest &lt; ActionController::TestCase
11 attr_accessor :profile, :friend, :community 11 attr_accessor :profile, :friend, :community
12 12
13 should 'add manually invitation of an added address with friend object on a queue and process it later' do 13 should 'add manually invitation of an added address with friend object on a queue and process it later' do
  14 + contact_list = ContactList.create
14 assert_difference Delayed::Job, :count, 1 do 15 assert_difference Delayed::Job, :count, 1 do
15 - post :friends, :profile => profile.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: <url>", :step => 2  
16 - assert_redirected_to :controller => 'friends' 16 + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: <url>", :contact_list => contact_list.id
  17 + assert_redirected_to :controller => 'profile', :action => 'friends'
17 end 18 end
18 19
19 assert_difference InviteFriend, :count, 1 do 20 assert_difference InviteFriend, :count, 1 do
@@ -22,9 +23,10 @@ class InviteControllerTest &lt; ActionController::TestCase @@ -22,9 +23,10 @@ class InviteControllerTest &lt; ActionController::TestCase
22 end 23 end
23 24
24 should 'add manually invitation of an added address with only email on a queue and process it later' do 25 should 'add manually invitation of an added address with only email on a queue and process it later' do
  26 + contact_list = ContactList.create
25 assert_difference Delayed::Job, :count, 1 do 27 assert_difference Delayed::Job, :count, 1 do
26 - post :friends, :profile => profile.identifier, :manual_import_addresses => "test@test.com", :import_from => "manual", :mail_template => "click: <url>", :step => 2  
27 - assert_redirected_to :controller => 'friends' 28 + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "test@test.com", :import_from => "manual", :mail_template => "click: <url>", :contact_list => contact_list.id
  29 + assert_redirected_to :controller => 'profile', :action => 'friends'
28 end 30 end
29 31
30 assert_difference InviteFriend, :count, 1 do 32 assert_difference InviteFriend, :count, 1 do
@@ -33,9 +35,10 @@ class InviteControllerTest &lt; ActionController::TestCase @@ -33,9 +35,10 @@ class InviteControllerTest &lt; ActionController::TestCase
33 end 35 end
34 36
35 should 'add manually invitation of an added address with email and other format on a queue and process it later' do 37 should 'add manually invitation of an added address with email and other format on a queue and process it later' do
  38 + contact_list = ContactList.create
36 assert_difference Delayed::Job, :count, 1 do 39 assert_difference Delayed::Job, :count, 1 do
37 - post :friends, :profile => profile.identifier, :manual_import_addresses => "test@test.cz.com", :import_from => "manual", :mail_template => "click: <url>", :step => 2  
38 - assert_redirected_to :controller => 'friends' 40 + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "test@test.cz.com", :import_from => "manual", :mail_template => "click: <url>", :contact_list => contact_list.id
  41 + assert_redirected_to :controller => 'profile', :action => 'friends'
39 end 42 end
40 43
41 assert_difference InviteFriend, :count, 1 do 44 assert_difference InviteFriend, :count, 1 do
@@ -44,9 +47,10 @@ class InviteControllerTest &lt; ActionController::TestCase @@ -44,9 +47,10 @@ class InviteControllerTest &lt; ActionController::TestCase
44 end 47 end
45 48
46 should 'add manually invitation of more than one added address on a queue and process it later' do 49 should 'add manually invitation of more than one added address on a queue and process it later' do
  50 + contact_list = ContactList.create
47 assert_difference Delayed::Job, :count, 1 do 51 assert_difference Delayed::Job, :count, 1 do
48 - post :friends, :profile => profile.identifier, :manual_import_addresses => "Some Friend <somefriend@email.com>\r\notherperson@bleble.net\r\n", :import_from => "manual", :mail_template => "click: <url>", :step => 2  
49 - assert_redirected_to :controller => 'friends' 52 + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "Some Friend <somefriend@email.com>\r\notherperson@bleble.net\r\n", :import_from => "manual", :mail_template => "click: <url>", :contact_list => contact_list.id
  53 + assert_redirected_to :controller => 'profile', :action => 'friends'
50 end 54 end
51 55
52 assert_difference InviteFriend, :count, 2 do 56 assert_difference InviteFriend, :count, 2 do
@@ -55,9 +59,10 @@ class InviteControllerTest &lt; ActionController::TestCase @@ -55,9 +59,10 @@ class InviteControllerTest &lt; ActionController::TestCase
55 end 59 end
56 60
57 should 'add manually invitation of an added address with name and e-mail on a queue and process it later' do 61 should 'add manually invitation of an added address with name and e-mail on a queue and process it later' do
  62 + contact_list = ContactList.create
58 assert_difference Delayed::Job, :count, 1 do 63 assert_difference Delayed::Job, :count, 1 do
59 - post :friends, :profile => profile.identifier, :manual_import_addresses => "Test Name <test@test.com>", :import_from => "manual", :mail_template => "click: <url>", :step => 2  
60 - assert_redirected_to :controller => 'friends' 64 + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "Test Name <test@test.com>", :import_from => "manual", :mail_template => "click: <url>", :contact_list => contact_list.id
  65 + assert_redirected_to :controller => 'profile', :action => 'friends'
61 end 66 end
62 67
63 assert_difference InviteFriend, :count, 1 do 68 assert_difference InviteFriend, :count, 1 do
@@ -66,9 +71,10 @@ class InviteControllerTest &lt; ActionController::TestCase @@ -66,9 +71,10 @@ class InviteControllerTest &lt; ActionController::TestCase
66 end 71 end
67 72
68 should 'add invitation of yourself on a queue and not process it later' do 73 should 'add invitation of yourself on a queue and not process it later' do
  74 + contact_list = ContactList.create
69 assert_difference Delayed::Job, :count, 1 do 75 assert_difference Delayed::Job, :count, 1 do
70 - post :friends, :profile => profile.identifier, :manual_import_addresses => "#{profile.name} <#{profile.user.email}>", :import_from => "manual", :mail_template => "click: <url>", :step => 2  
71 - assert_redirected_to :controller => 'friends' 76 + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "#{profile.name} <#{profile.user.email}>", :import_from => "manual", :mail_template => "click: <url>", :contact_list => contact_list.id
  77 + assert_redirected_to :controller => 'profile', :action => 'friends'
72 end 78 end
73 79
74 assert_no_difference InviteFriend, :count do 80 assert_no_difference InviteFriend, :count do
@@ -80,9 +86,10 @@ class InviteControllerTest &lt; ActionController::TestCase @@ -80,9 +86,10 @@ class InviteControllerTest &lt; ActionController::TestCase
80 friend = create_user('testfriend', :email => 'friend@noosfero.org') 86 friend = create_user('testfriend', :email => 'friend@noosfero.org')
81 friend.person.add_friend(profile) 87 friend.person.add_friend(profile)
82 88
  89 + contact_list = ContactList.create
83 assert_difference Delayed::Job, :count, 1 do 90 assert_difference Delayed::Job, :count, 1 do
84 - post :friends, :profile => profile.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: <url>", :step => 2  
85 - assert_redirected_to :controller => 'friends' 91 + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: <url>", :contact_list => contact_list.id
  92 + assert_redirected_to :controller => 'profile', :action => 'friends'
86 end 93 end
87 94
88 assert_no_difference InviteFriend, :count do 95 assert_no_difference InviteFriend, :count do
@@ -91,42 +98,131 @@ class InviteControllerTest &lt; ActionController::TestCase @@ -91,42 +98,131 @@ class InviteControllerTest &lt; ActionController::TestCase
91 end 98 end
92 99
93 should 'display invitation page' do 100 should 'display invitation page' do
94 - get :friends, :profile => profile.identifier 101 + get :select_address_book, :profile => profile.identifier
95 assert_response :success 102 assert_response :success
96 assert_tag :tag => 'h1', :content => 'Invite your friends' 103 assert_tag :tag => 'h1', :content => 'Invite your friends'
97 end 104 end
98 105
99 should 'get mail template to invite members' do 106 should 'get mail template to invite members' do
100 community.add_admin(profile) 107 community.add_admin(profile)
101 - get :friends, :profile => community.identifier 108 + contact_list = ContactList.create
  109 + get :select_friends, :profile => community.identifier, :contact_list => contact_list.id
102 assert_equal InviteMember.mail_template, assigns(:mail_template) 110 assert_equal InviteMember.mail_template, assigns(:mail_template)
103 end 111 end
104 112
105 should 'get mail template to invite friends' do 113 should 'get mail template to invite friends' do
106 community.add_admin(profile) 114 community.add_admin(profile)
107 - get :friends, :profile => profile.identifier 115 + contact_list = ContactList.create
  116 + get :select_friends, :profile => profile.identifier, :contact_list => contact_list.id
108 assert_equal InviteFriend.mail_template, assigns(:mail_template) 117 assert_equal InviteFriend.mail_template, assigns(:mail_template)
109 end 118 end
110 119
111 - should 'deny if user has no rights to invite members' do  
112 - get :friends, :profile => community.identifier 120 + should 'deny select_address_book f user has no rights to invite members' do
  121 + get :select_address_book, :profile => community.identifier
113 assert_response 403 # forbidden 122 assert_response 403 # forbidden
114 end 123 end
115 124
116 - should 'deny access when trying to invite friends to another user' do  
117 - get :friends, :profile => friend.identifier 125 + should 'deny select_friends if user has no rights to invite members' do
  126 + get :select_friends, :profile => community.identifier
118 assert_response 403 # forbidden 127 assert_response 403 # forbidden
119 end 128 end
120 129
121 - should 'redirect to friends after invitation if profile is a person' do  
122 - post :friends, :profile => profile.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: <url>", :step => 2  
123 - assert_redirected_to :controller => 'friends' 130 + should 'deny select_address_book access when trying to invite friends to another user' do
  131 + get :select_address_book, :profile => friend.identifier
  132 + assert_response 403 # forbidden
  133 + end
  134 +
  135 + should 'deny select_friends access when trying to invite friends to another user' do
  136 + get :select_address_book, :profile => friend.identifier
  137 + assert_response 403 # forbidden
  138 + end
  139 +
  140 + should 'redirect to profile after invitation if profile is a person' do
  141 + contact_list = ContactList.create
  142 + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: <url>", :contact_list => contact_list.id
  143 + assert_redirected_to :controller => 'profile', :action => 'friends'
124 end 144 end
125 145
126 - should 'redirect to friends after invitation if profile is not a person' do 146 + should 'redirect to profile after invitation if profile is not a person' do
127 community.add_admin(profile) 147 community.add_admin(profile)
128 - post :friends, :profile => community.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: <url>", :step => 2  
129 - assert_redirected_to :controller => 'profile_members' 148 + contact_list = ContactList.create
  149 + post :select_friends, :profile => community.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: <url>", :contact_list => contact_list.id
  150 + assert_redirected_to :controller => 'profile', :action => 'members'
  151 + end
  152 +
  153 + should 'create a job to get emails after choose address book' do
  154 + community.add_admin(profile)
  155 + contact_list = ContactList.create
  156 + assert_difference Delayed::Job, :count, 1 do
  157 + post :select_address_book, :profile => community.identifier, :contact_list => contact_list.id, :import_from => 'gmail'
  158 + assert_redirected_to :action => 'select_friends'
  159 + end
  160 + end
  161 +
  162 + should 'destroy contact_list after invitation when import is manual' do
  163 + contact_list = ContactList.create
  164 + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: <url>", :contact_list => contact_list.id
  165 +
  166 + assert ContactList.exists?(contact_list.id)
  167 + Delayed::Worker.new.work_off
  168 + assert !ContactList.exists?(contact_list.id)
  169 + end
  170 +
  171 + should 'destroy contact_list after invitation when import is not manual' do
  172 + contact_list = ContactList.create
  173 + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "not_manual", :mail_template => "click: <url>", :contact_list => contact_list.id
  174 +
  175 + assert ContactList.exists?(contact_list.id)
  176 + Delayed::Worker.new.work_off
  177 + assert !ContactList.exists?(contact_list.id)
  178 + end
  179 +
  180 + should 'return empty hash as invitation data if contact list was not fetched' do
  181 + contact_list = ContactList.create
  182 + get :invitation_data, :profile => profile.identifier, :contact_list => contact_list.id
  183 +
  184 + assert_equal 'application/javascript', @response.content_type
  185 + assert_equal '{}', @response.body
  186 + end
  187 +
  188 + should 'return hash as invitation data if contact list was fetched' do
  189 + contact_list = ContactList.create(:fetched => true)
  190 + get :invitation_data, :profile => profile.identifier, :contact_list => contact_list.id
  191 +
  192 + assert_equal 'application/javascript', @response.content_type
  193 + assert_equal "{\"fetched\": true, \"contact_list\": #{contact_list.id}, \"error\": null}", @response.body
  194 + end
  195 +
  196 + should 'render empty list of contacts' do
  197 + contact_list = ContactList.create(:fetched => true)
  198 + get :add_contact_list, :profile => profile.identifier, :contact_list => contact_list.id
  199 +
  200 + assert_response :success
  201 + assert_template '_contact_list'
  202 + assert_no_tag(:tag => 'input', :attributes => { :type => 'checkbox', :name => 'webmail_import_addresses[]'})
  203 + end
  204 +
  205 + should 'render list of contacts' do
  206 + contact_list = ContactList.create(:fetched => true, :list => ['email1@noosfero.org', 'email2@noosfero.org'])
  207 + get :add_contact_list, :profile => profile.identifier, :contact_list => contact_list.id
  208 +
  209 + assert_response :success
  210 + assert_template '_contact_list'
  211 +
  212 + i = 0
  213 + contact_list.list.each do |contact|
  214 + i += 1
  215 + assert_tag(:tag => 'input', :attributes => { :type => 'checkbox', :name => 'webmail_import_addresses[]', :id => "contacts_to_invite_#{i}", :value => contact[2]})
  216 + end
  217 + end
  218 +
  219 + should 'destroy contact_list when cancel_fetching_emails' do
  220 + contact_list = ContactList.create
  221 +
  222 + assert_difference ContactList, :count, -1 do
  223 + get :cancel_fetching_emails, :profile => profile.identifier, :contact_list => contact_list.id
  224 + end
  225 + assert_redirected_to :action => 'select_address_book'
130 end 226 end
131 227
132 end 228 end
test/unit/contact_list_test.rb 0 → 100644
@@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class ContactListTest < ActiveSupport::TestCase
  4 +
  5 + should 'have list as an array' do
  6 + assert_equal [], ContactList.create.list
  7 + end
  8 +
  9 + should 'display list' do
  10 + contact_list = ContactList.create(:list => ['email1@noosfero.org', 'email2@noosfero.org'])
  11 +
  12 + assert_equal ['email1@noosfero.org', 'email2@noosfero.org'], contact_list.list
  13 + end
  14 +
  15 + should 'return empty hash if contact list was not fetched' do
  16 + contact_list = ContactList.create
  17 + assert_equal({}, contact_list.data)
  18 + end
  19 +
  20 + should 'return hash if contact list was fetched' do
  21 + contact_list = ContactList.create(:fetched => true)
  22 + assert_equal({"fetched" => true, "contact_list" => contact_list.id, "error" => contact_list.error_fetching}, contact_list.data)
  23 + end
  24 +
  25 + should 'update fetched and error_fetching when register auth error' do
  26 + contact_list = ContactList.create
  27 + assert_equal({}, contact_list.data)
  28 +
  29 + contact_list.register_error
  30 + assert_equal({"fetched" => true, "contact_list" => contact_list.id, "error" => 'There was an error while looking for your contact list. Please, try again'}, contact_list.data)
  31 + end
  32 +
  33 + should 'update fetched and error_fetching when register error' do
  34 + contact_list = ContactList.create
  35 + assert_equal({}, contact_list.data)
  36 +
  37 + contact_list.register_auth_error
  38 + assert_equal({"fetched" => true, "contact_list" => contact_list.id, "error" => 'There was an error while authenticating. Did you enter correct login and password?'}, contact_list.data)
  39 + end
  40 +
  41 +end
test/unit/get_email_contacts_job_test.rb 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class GetEmailContactsJobTest < ActiveSupport::TestCase
  4 +
  5 + should 'register error' do
  6 + contact_list = ContactList.create
  7 + Invitation.expects(:get_contacts).with('from-email', 'mylogin', 'mypassword', contact_list.id).raises(Exception.new("crash"))
  8 +
  9 + job = GetEmailContactsJob.new('from-email', 'mylogin', 'mypassword', contact_list.id)
  10 + job.perform
  11 +
  12 + assert ContactList.find(contact_list).fetched
  13 + assert_equal 'There was an error while looking for your contact list. Please, try again', ContactList.find(contact_list).error_fetching
  14 + end
  15 +
  16 + should 'register auth error' do
  17 + contact_list = ContactList.create
  18 + Invitation.expects(:get_contacts).with('from-email', 'mylogin', 'wrongpassword', contact_list.id).raises(Contacts::AuthenticationError)
  19 +
  20 + job = GetEmailContactsJob.new('from-email', 'mylogin', 'wrongpassword', contact_list.id)
  21 + job.perform
  22 +
  23 + assert ContactList.find(contact_list).fetched
  24 + assert_equal 'There was an error while authenticating. Did you enter correct login and password?', ContactList.find(contact_list).error_fetching
  25 + end
  26 +
  27 +end
test/unit/invitation_test.rb
@@ -26,8 +26,9 @@ class InvitationTest &lt; ActiveSupport::TestCase @@ -26,8 +26,9 @@ class InvitationTest &lt; ActiveSupport::TestCase
26 end 26 end
27 27
28 should 'raises when try get contacts from unknown source' do 28 should 'raises when try get contacts from unknown source' do
  29 + contact_list = ContactList.create
29 assert_raise NotImplementedError do 30 assert_raise NotImplementedError do
30 - Invitation.get_contacts('ze', 'ze12', 'bli-mail') 31 + Invitation.get_contacts('ze', 'ze12', 'bli-mail', contact_list.id)
31 end 32 end
32 end 33 end
33 34
@@ -71,4 +72,29 @@ class InvitationTest &lt; ActiveSupport::TestCase @@ -71,4 +72,29 @@ class InvitationTest &lt; ActiveSupport::TestCase
71 end 72 end
72 end 73 end
73 74
  75 + should 'add url on message if user removed it' do
  76 + person = create_user('testuser1').person
  77 + friend = create_user('testuser2').person
  78 + invitation = Invitation.create!(
  79 + :person => person,
  80 + :friend => friend,
  81 + :message => 'Hi <friend>, <user> is inviting you!'
  82 + )
  83 + assert_equal "Hi <friend>, <user> is inviting you!#{invitation.message_to_accept_invitation}", invitation.message
  84 + end
  85 +
  86 + should 'do nothing with message if user added url' do
  87 + person = create_user('testuser1').person
  88 + friend = create_user('testuser2').person
  89 + invitation = Invitation.create!(
  90 + :person => person,
  91 + :friend => friend,
  92 + :message => 'Hi <friend>, <user> is inviting you to be his friend on <url>!'
  93 + )
  94 + assert_equal "Hi <friend>, <user> is inviting you to be his friend on <url>!", invitation.message
  95 + end
  96 +
  97 + should 'have a message with url' do
  98 + assert_equal "<p>To accept invitation, please follow this link: <url></p>", Invitation.new.message_to_accept_invitation
  99 + end
74 end 100 end
test/unit/invite_friend_test.rb
@@ -70,21 +70,6 @@ class InviteFriendTest &lt; ActiveSupport::TestCase @@ -70,21 +70,6 @@ class InviteFriendTest &lt; ActiveSupport::TestCase
70 ok('must validate with no target') { !task.errors.invalid?(:target_id) } 70 ok('must validate with no target') { !task.errors.invalid?(:target_id) }
71 end 71 end
72 72
73 - should 'require message with <url> tag if no target given' do  
74 - task = InviteFriend.new  
75 - task.valid?  
76 -  
77 - ok('must not validate with no message') { task.errors.invalid?(:message) }  
78 -  
79 - task.message = 'a simple message'  
80 - task.valid?  
81 - ok('must not validate with no <url> tag in message') { task.errors.invalid?(:message) }  
82 -  
83 - task.message = 'a simple message with <url>'  
84 - task.valid?  
85 - ok('must validate when message is given with <url> tag') { !task.errors.invalid?(:message)}  
86 - end  
87 -  
88 should 'dont require message if target given (person being invited)' do 73 should 'dont require message if target given (person being invited)' do
89 task = InviteFriend.new(:target => create_user('testuser2').person) 74 task = InviteFriend.new(:target => create_user('testuser2').person)
90 task.valid? 75 task.valid?