diff --git a/app/controllers/public/invite_controller.rb b/app/controllers/public/invite_controller.rb index e7e310e..2fa0b1f 100644 --- a/app/controllers/public/invite_controller.rb +++ b/app/controllers/public/invite_controller.rb @@ -2,42 +2,57 @@ class InviteController < PublicController needs_profile before_filter :login_required - before_filter :check_permissions_to_invite, :only => 'friends' + before_filter :check_permissions_to_invite - def friends - step = params[:step] + def select_address_book + @import_from = params[:import_from] || "manual" if request.post? - if step == '1' - begin - @contacts = Invitation.get_contacts(params[:import_from], params[:login], params[:password]) - rescue - @login = params[:login] - flash.now[:notice] = _('There was an error while looking for your contact list. Did you enter correct login and password?') - end - elsif step == '2' - manual_import_addresses = params[:manual_import_addresses] - webmail_import_addresses = params[:webmail_import_addresses] - contacts_to_invite = Invitation.join_contacts(manual_import_addresses, webmail_import_addresses) - if !params[:mail_template].match(//) - flash.now[:notice] = _('<url> is needed in invitation mail.') - elsif !contacts_to_invite.empty? - Delayed::Job.enqueue InvitationJob.new(user.id, contacts_to_invite, params[:mail_template], profile.id) - session[:notice] = _('Your invitations are being sent.') - if profile.person? - redirect_to :controller => 'friends' - else - redirect_to :controller => 'profile_members' - end + contact_list = ContactList.create + Delayed::Job.enqueue GetEmailContactsJob.new(@import_from, params[:login], params[:password], contact_list.id) if @import_from != 'manual' + redirect_to :action => 'select_friends', :contact_list => contact_list.id, :import_from => @import_from + end + end + + def select_friends + @contact_list = ContactList.find(params[:contact_list]) + @mail_template = params[:mail_template] || environment.invitation_mail_template(profile) + @import_from = params[:import_from] || "manual" + if request.post? + manual_import_addresses = params[:manual_import_addresses] + webmail_import_addresses = params[:webmail_import_addresses] + contacts_to_invite = Invitation.join_contacts(manual_import_addresses, webmail_import_addresses) + if !contacts_to_invite.empty? + Delayed::Job.enqueue InvitationJob.new(current_user.person.id, contacts_to_invite, params[:mail_template], profile.id, @contact_list.id) + session[:notice] = _('Your invitations are being sent.') + if profile.person? + redirect_to :controller => 'profile', :action => 'friends' else - flash.now[:notice] = _('Please enter a valid email address.') + redirect_to :controller => 'profile', :action => 'members' end - @contacts = params[:webmail_friends] ? params[:webmail_friends].map {|e| YAML.load(e)} : [] - @manual_import_addresses = manual_import_addresses || "" - @webmail_import_addresses = webmail_import_addresses || [] + return + else + session[:notice] = _('Please enter a valid email address.') end + @manual_import_addresses = manual_import_addresses || "" + @webmail_import_addresses = webmail_import_addresses || [] end - @import_from = params[:import_from] || "manual" - @mail_template = params[:mail_template] || environment.invitation_mail_template(profile) + end + + def invitation_data + contact_list = ContactList.find(params[:contact_list]) + render :text => contact_list.data.to_json, :layout => false, :content_type => "application/javascript" + end + + def add_contact_list + contact_list = ContactList.find(params[:contact_list]) + contacts = contact_list.list + render :partial => 'invite/contact_list', :locals => {:contacts => contacts} + end + + def cancel_fetching_emails + contact_list = ContactList.find(params[:contact_list]) + contact_list.destroy + redirect_to :action => 'select_address_book' end protected diff --git a/app/models/contact_list.rb b/app/models/contact_list.rb new file mode 100644 index 0000000..7fc42ca --- /dev/null +++ b/app/models/contact_list.rb @@ -0,0 +1,27 @@ +class ContactList < ActiveRecord::Base + + serialize :list, Array + + def list + self[:list] || [] + end + + def data + if self.fetched + { "fetched" => true, "contact_list" => self.id, "error" => self.error_fetching } + else + {} + end + end + + def register_auth_error + msg = _('There was an error while authenticating. Did you enter correct login and password?') + self.update_attributes(:fetched => true, :error_fetching => msg) + end + + def register_error + msg = _('There was an error while looking for your contact list. Please, try again') + self.update_attributes(:fetched => true, :error_fetching => msg) + end + +end diff --git a/app/models/invitation.rb b/app/models/invitation.rb index 090239c..f6be288 100644 --- a/app/models/invitation.rb +++ b/app/models/invitation.rb @@ -11,7 +11,6 @@ class Invitation < Task validates_format_of :friend_email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => Proc.new{|invite| invite.target_id.blank?} validates_presence_of :message, :if => Proc.new{|invite| invite.target_id.blank?} - validates_format_of :message, :with => //, :if => Proc.new{|invite| invite.target_id.blank?} alias :person :requestor alias :person= :requestor= @@ -19,6 +18,12 @@ class Invitation < Task alias :friend :target alias :friend= :target= + before_create do |task| + if task.message && !task.message.match(//) + task.message += task.message_to_accept_invitation + end + end + after_create do |task| TaskMailer.deliver_invitation_notification(task) unless task.friend end @@ -72,21 +77,26 @@ class Invitation < Task end end - def self.get_contacts(source, login, password) - contacts = [] + def self.get_contacts(source, login, password, contact_list_id) + contact_list = ContactList.find(contact_list_id) case source when "gmail" - contacts = Contacts::Gmail.new(login, password).contacts + email_service = Contacts::Gmail.new(login, password) when "yahoo" - contacts = Contacts::Yahoo.new(login, password).contacts + email_service = Contacts::Yahoo.new(login, password) when "hotmail" - contacts = Contacts::Hotmail.new(login, password).contacts + email_service = Contacts::Hotmail.new(login, password) when "manual" #do nothing else raise NotImplementedError, 'Unknown source to get contacts' end - contacts.map { |contact| contact + ["#{contact[0]} <#{contact[1]}>"] } + if email_service + contact_list.list = email_service.contacts.map { |contact| contact + ["#{contact[0]} <#{contact[1]}>"] } + contact_list.fetched = true + contact_list.save + end + contact_list.list end def self.join_contacts(manual_import_addresses, webmail_import_addresses) @@ -112,4 +122,7 @@ class Invitation < Task raise 'You should implement mail_template in a subclass' end + def message_to_accept_invitation + '

' + _('To accept invitation, please follow this link: ') + '

' + end end diff --git a/app/views/friends/index.rhtml b/app/views/friends/index.rhtml index a3db3eb..62a2492 100644 --- a/app/views/friends/index.rhtml +++ b/app/views/friends/index.rhtml @@ -14,7 +14,7 @@ <% button_bar do %> <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %> - <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'friends') %> + <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'select_address_book') %> <% end %> <% end %> @@ -40,11 +40,11 @@ <%= pagination_links @friends, :param_name => 'npage' %> -<% button_bar do %> - <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> - <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %> - <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'friends') %> -<% end %> + <% button_bar do %> + <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> + <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %> + <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'select_address_book') %> + <% end %> <% end %> diff --git a/app/views/invite/_contact_list.rhtml b/app/views/invite/_contact_list.rhtml new file mode 100644 index 0000000..2f3ab6c --- /dev/null +++ b/app/views/invite/_contact_list.rhtml @@ -0,0 +1,12 @@ +<% friend_pos = 0 %> +<% contacts.each do |contact| %> + <% friend_pos += 1 %> +

+ <%= check_box_tag("webmail_import_addresses[]", contact[2], + (!@webmail_import_addresses || @webmail_import_addresses.include?(contact[2])), + :id => "contacts_to_invite_#{friend_pos}", + :class => "contact_to_invite" ) + %> + +

+<% end %> diff --git a/app/views/invite/_dialog_wait_loading.rhtml b/app/views/invite/_dialog_wait_loading.rhtml new file mode 100644 index 0000000..360723c --- /dev/null +++ b/app/views/invite/_dialog_wait_loading.rhtml @@ -0,0 +1,23 @@ +<% javascript_tag do %> + jQuery(function($) { + $("#loading-dialog").dialog({ + height: 160, + width: 450, + modal: true, + resizable: false, + title: "<%= ui_icon('ui-icon-info') + _('Please, wait...') %>", + open: check_contact_list('<%= contact_list.to_s %>'), + }); + }); +<% end %> + + +
+

<%= _('Your e-mails contacts are being fetched') %>

+

<%= _('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.') %> + + <%= link_to(_('Verify contact list'), {:action => 'invitation_data', :contact_list => @contact_list}, :id => "verify-contact-list", :style => 'display:none') %> + <%= link_to(_('Add contact list'), {:action => 'add_contact_list', :contact_list => @contact_list}, :id => "add-contact-list", :style => 'display:none') %> + <%= link_to(_('Cancel fetching e-mails'), {:action => 'cancel_fetching_emails', :contact_list => @contact_list}, :id => "cancel-fetching-emails", :style => 'display:none') %> +

+ diff --git a/app/views/invite/friends.rhtml b/app/views/invite/friends.rhtml deleted file mode 100644 index 170bc2e..0000000 --- a/app/views/invite/friends.rhtml +++ /dev/null @@ -1,93 +0,0 @@ -<% if profile.person? %> -

<%= _('Invite your friends') %>

-<% else %> -

<%= _('Invite your friends to join %s') % profile.name %>

-<% end %> - -<% unless @contacts %> - -

<%= _('Step 1 of 2: Select address book') %>

- - <% form_tag do %> - <%= hidden_field_tag(:step, 1) %> - - <%= [ - 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"), - radio_button_tag(:import_from, "gmail", @import_from == "gmail", :onclick => 'show_invite_friend_login_password()') + content_tag('label', 'Gmail', :for => 'import_from_gmail'), - radio_button_tag(:import_from, "yahoo", @import_from == "yahoo", :onclick => 'show_invite_friend_login_password()') + content_tag('label', 'Yahoo', :for => "import_from_yahoo"), - radio_button_tag(:import_from, "hotmail", @import_from == "hotmail", :onclick => 'show_invite_friend_login_password()') + content_tag('label', 'Hotmail', :for => "import_from_hotmail") - ].join("\n
\n") %> - - -
> - <%= labelled_form_field(_("Username") + ":", text_field_tag(:login, @login)) %> - <%= labelled_form_field(_("Password") + ":", password_field_tag(:password)) %> -
- - <% button_bar do %> - <%= submit_button(:forward, _("Next")) %> - <% end %> -

<%= _("We won't store your password or contact anyone without your permission.") %>

- <% end %> - -<% else %> - -

<%= _('Step 2 of 2: Selecting Friends') %>

-

- <%= _('Indicate which friends you want to invite.') %> -

- - <% form_tag do %> - <%= hidden_field_tag(:step, 2) %> - <%= hidden_field_tag(:import_from, @import_from) %> - -
- <%= labelled_form_field(_('Enter one e-mail address per line:'), text_area_tag(:manual_import_addresses, (@manual_import_addresses || ''), :cols => 72, :rows => 5)) %> -
- <% if @import_from != 'manual' %> -
- <%= link_to_function _('Check all'), "$$('input.contact_to_invite').each(function(checkbox) { checkbox.checked = true; });" %> - <%= link_to_function _('Uncheck all'), "$$('input.contact_to_invite').each(function(checkbox) { checkbox.checked = false; });" %> - <% friend_pos = 0 %> -
- <% @contacts.each do |contact| %> - <% friend_pos += 1 %> -

- <%= hidden_field_tag("webmail_friends[]", contact.to_yaml) %> - <%= check_box_tag("webmail_import_addresses[]", contact[2], - (!@webmail_import_addresses || @webmail_import_addresses.include?(contact[2])), - :id => "contacts_to_invite_#{friend_pos}", - :class => "contact_to_invite" ) - %> - -

- <% end %> -
-
- <% end -%> - -
- - <%= link_to_function(_('Personalize invitation mail'), nil) do |page| - page['invitation-mail_template'].show - end %> - - - - <% button_bar do %> - <%= submit_button(:ok, _("Invite my friends!")) %> - <% end %> - <% end %> - -<% end %> diff --git a/app/views/invite/select_address_book.rhtml b/app/views/invite/select_address_book.rhtml new file mode 100644 index 0000000..64b348c --- /dev/null +++ b/app/views/invite/select_address_book.rhtml @@ -0,0 +1,51 @@ +<% if profile.person? %> +

<%= _('Invite your friends') %>

+<% else %> +

<%= _('Invite your friends to join %s') % profile.name %>

+<% end %> + +

<%= _('Step 1 of 2: Select address book') %>

+ +<% form_tag do %> + + <%= [ + 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"), + 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'), + 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"), + 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") + ].join("\n
\n") %> + + +
> +
+ <%= ui_icon('ui-icon-alert') %> + <%= _('Please type your username in the format yourname@example.com') %> +
+ + <%= labelled_form_field(_("Username") + ":", text_field_tag(:login, @login)) %> + <%= labelled_form_field(_("Password") + ":", password_field_tag(:password)) %> +
+ + <% button_bar do %> + <%= submit_button(:forward, _("Next")) %> + <% end %> +

<%= _("We won't store your password or contact anyone without your permission.") %>

+<% end %> + +
+ + + diff --git a/app/views/invite/select_friends.rhtml b/app/views/invite/select_friends.rhtml new file mode 100644 index 0000000..395c73f --- /dev/null +++ b/app/views/invite/select_friends.rhtml @@ -0,0 +1,47 @@ +<%= render :partial => 'invite/dialog_wait_loading', :locals => {:contact_list => @contact_list.id } if @import_from != 'manual' %> + +<% if profile.person? %> +

<%= _('Invite your friends') %>

+<% else %> +

<%= _('Invite your friends to join %s') % profile.name %>

+<% end %> + + +

<%= _('Step 2 of 2: Selecting Friends') %>

+ +<%= button(:back, _('Back'), { :action => 'select_address_book' }, :id => 'invitation_back_button') %> + +

+<%= _('Indicate which friends you want to invite.') %> +

+ +<% form_tag do %> + <%= hidden_field_tag(:import_from, @import_from) %> + <%= hidden_field_tag(:contact_list, @contact_list.id) %> + +
+ <%= labelled_form_field(_('Enter one e-mail address per line:'), text_area_tag(:manual_import_addresses, (@manual_import_addresses || ''), :cols => 72, :rows => 5)) %> +
+ <% if @import_from != 'manual' %> +
+ <%= link_to_function _('Check all'), "$$('input.contact_to_invite').each(function(checkbox) { checkbox.checked = true; });" %> + <%= link_to_function _('Uncheck all'), "$$('input.contact_to_invite').each(function(checkbox) { checkbox.checked = false; });" %> +
+
+ <% end -%> + +
+ + <%= link_to_function(_('Personalize invitation mail'), nil) do |page| + page['invitation-mail_template'].show + end %> + + + + <% button_bar do %> + <%= submit_button(:ok, _("Invite my friends!")) %> + <% end %> +<% end %> diff --git a/app/views/profile/friends.rhtml b/app/views/profile/friends.rhtml index b1d611d..385ad8a 100644 --- a/app/views/profile/friends.rhtml +++ b/app/views/profile/friends.rhtml @@ -18,7 +18,7 @@ <%= button :back, _('Go back'), { :controller => 'profile' } %> <% if user == profile %> <%= button :edit, _('Manage my friends'), :controller => 'friends', :action => 'index', :profile => profile.identifier %> - <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'friends') %> + <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'select_address_book') %> <% end %> <% end %> diff --git a/app/views/profile/members.rhtml b/app/views/profile/members.rhtml index 09a60e1..7a76177 100644 --- a/app/views/profile/members.rhtml +++ b/app/views/profile/members.rhtml @@ -17,7 +17,7 @@ <% button_bar do %> <%= button :back, _('Go back'), { :controller => 'profile' } %> <% if profile.community? and user and user.has_permission?(:invite_members, profile) %> - <%= button :search, _('Invite your friends to join %s') % profile.name, :controller => 'invite', :action => 'friends' %> + <%= button :search, _('Invite your friends to join %s') % profile.name, :controller => 'invite', :action => 'selects_address_book' %> <% end %> <% end %> diff --git a/app/views/profile_members/index.rhtml b/app/views/profile_members/index.rhtml index a8e87fc..9892e8e 100644 --- a/app/views/profile_members/index.rhtml +++ b/app/views/profile_members/index.rhtml @@ -6,6 +6,6 @@ <%= button :back, _('Back'), :controller => 'profile_editor' %> <%= button :add, _('Add members'), :action => 'add_members' if profile.enterprise? %> <% if profile.community? and user.has_permission?(:invite_members, profile) %> - <%= button :search, _('Invite your friends to join %s') % profile.name, :controller => 'invite', :action => 'friends' %> + <%= button :search, _('Invite your friends to join %s') % profile.name, :controller => 'invite', :action => 'select_address_book' %> <% end %> <% end %> diff --git a/config/initializers/delayed_job_config.rb b/config/initializers/delayed_job_config.rb new file mode 100644 index 0000000..39f5a77 --- /dev/null +++ b/config/initializers/delayed_job_config.rb @@ -0,0 +1,2 @@ +Delayed::Worker.max_attempts = 2 +Delayed::Worker.max_run_time = 10.minutes diff --git a/db/migrate/20100823190348_create_contact_lists.rb b/db/migrate/20100823190348_create_contact_lists.rb new file mode 100644 index 0000000..9f77124 --- /dev/null +++ b/db/migrate/20100823190348_create_contact_lists.rb @@ -0,0 +1,14 @@ +class CreateContactLists < ActiveRecord::Migration + def self.up + create_table :contact_lists do |t| + t.text :list + t.string :error_fetching + t.boolean :fetched, :default => false + t.timestamps + end + end + + def self.down + drop_table :contact_lists + end +end diff --git a/db/schema.rb b/db/schema.rb index e44f522..71ab9f4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -9,7 +9,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20100822034415) do +ActiveRecord::Schema.define(:version => 20100823190348) do create_table "article_versions", :force => true do |t| t.integer "article_id" @@ -145,9 +145,9 @@ ActiveRecord::Schema.define(:version => 20100822034415) do t.string "name", :null => false t.string "description" t.string "link" + t.integer "environment_id" t.datetime "created_at" t.datetime "updated_at" - t.integer "environment_id" end create_table "comments", :force => true do |t| @@ -160,6 +160,14 @@ ActiveRecord::Schema.define(:version => 20100822034415) do t.datetime "created_at" end + create_table "contact_lists", :force => true do |t| + t.text "list" + t.string "error_fetching" + t.boolean "fetched", :default => false + t.datetime "created_at" + t.datetime "updated_at" + end + create_table "delayed_jobs", :force => true do |t| t.integer "priority", :default => 0 t.integer "attempts", :default => 0 @@ -351,9 +359,9 @@ ActiveRecord::Schema.define(:version => 20100822034415) do create_table "roles", :force => true do |t| t.string "name" + t.text "permissions" t.string "key" t.boolean "system", :default => false - t.text "permissions" t.integer "environment_id" end diff --git a/features/invitation.feature b/features/invitation.feature index 27d1703..247e216 100644 --- a/features/invitation.feature +++ b/features/invitation.feature @@ -32,15 +32,14 @@ Feature: invitation When I am on /profile/josesilva/invite/friends Then I should see "Invite your friends" - # why not work? - Scenario: back to manage friends after invite friends + Scenario: back to friends after invite friends Given I am on /myprofile/josesilva/friends And I follow "Invite people from my e-mail contacts" And I press "Next" And I fill in "manual_import_addresses" with "misfits@devil.doll" And I fill in "mail_template" with "Follow this link " When I press "Invite my friends!" - Then I should be on /myprofile/josesilva/friends + Then I should be on /profile/josesilva/friends Scenario: see link to invite members to community When I am on /profile/26-bsslines/members @@ -75,14 +74,14 @@ Feature: invitation Given I am on Beatles For Sale's members management Then I should not see "Invite your friends to join Beatles For Sale" link - Scenario: back to manage members after invite friends + Scenario: back to members after invite friends to join a community Given I am on 26 Bsslines's members management And I follow "Invite your friends to join 26 Bsslines" And I press "Next" And I fill in "manual_import_addresses" with "misfits@devil.doll" And I fill in "mail_template" with "Follow this link " When I press "Invite my friends!" - Then I should be on /myprofile/26-bsslines/profile_members + Then I should be on /profile/26-bsslines/members Scenario: noosfero user receives a task when a user invites to join a community Given I am on 26 Bsslines's members management diff --git a/lib/get_email_contacts_job.rb b/lib/get_email_contacts_job.rb new file mode 100644 index 0000000..92a8199 --- /dev/null +++ b/lib/get_email_contacts_job.rb @@ -0,0 +1,11 @@ +class GetEmailContactsJob < Struct.new(:import_from, :login, :password, :contact_list_id) + def perform + begin + Invitation.get_contacts(import_from, login, password, contact_list_id) + rescue Contacts::AuthenticationError => ex + ContactList.find(contact_list_id).register_auth_error + rescue Exception => ex + ContactList.find(contact_list_id).register_error + end + end +end diff --git a/lib/invitation_job.rb b/lib/invitation_job.rb index f15fb32..043d1af 100644 --- a/lib/invitation_job.rb +++ b/lib/invitation_job.rb @@ -1,11 +1,12 @@ -class InvitationJob < Struct.new(:person_id, :contacts_to_invite, :message, :profile_id) +class InvitationJob < Struct.new(:person_id, :contacts_to_invite, :message, :profile_id, :contact_list_id) def perform begin - person = Person.find(person_id) - profile = Profile.find(profile_id) - Invitation.invite(person, contacts_to_invite, message, profile) + person = Person.find(person_id) + profile = Profile.find(profile_id) + Invitation.invite(person, contacts_to_invite, message, profile) + ContactList.find(contact_list_id).destroy rescue ActiveRecord::NotFound => e - # ... + #... end end end diff --git a/public/javascripts/application.js b/public/javascripts/application.js index d4b966e..5ae4ccf 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -455,9 +455,46 @@ jQuery(function($) { $('#user .not-logged-in, .login-block .not-logged-user').fadeIn(); } if (data.notice) { - var $noticeBox = $('
').html(data.notice).appendTo('body').fadeTo('fast', 0.8); - $noticeBox.click(function() { $(this).hide(); }); - setTimeout(function() { $noticeBox.fadeOut('fast'); }, 5000); + display_notice(data.notice); } }); }); + +// controls the display of contact list +function check_contact_list(contact_list) { + jQuery(function($) { + var verify_url = $('#verify-contact-list').attr('href'); + var add_contacts_url = $('#add-contact-list').attr('href'); + var cancel_contacts_fetching_url = $('#cancel-fetching-emails').attr('href'); + var interval = setInterval(function() { + $.getJSON(verify_url, function(data) { + if (data.fetched) { + clearInterval(interval); + if (data.error) { + $("#loading-dialog").dialog('close'); + $.get(cancel_contacts_fetching_url); + redirect_to($('#invitation_back_button').attr('href')); + display_notice(data.error); + } else { + $.get(add_contacts_url, function(data){ + $("#contacts-list").html(data); + }); + }; + $("#loading-dialog").dialog('close'); + } + }); + }, 5000); + setTimeout(function() { + clearInterval(interval); + $("#loading-dialog").dialog('close'); + $.get(cancel_contacts_fetching_url); + redirect_to($('#invitation_back_button').attr('href')); + }, 600000); + }); +} + +function display_notice(message) { + var $noticeBox = jQuery('
').html(message).appendTo('body').fadeTo('fast', 0.8); + $noticeBox.click(function() { $(this).hide(); }); + setTimeout(function() { $noticeBox.fadeOut('fast'); }, 5000); +} diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index 8bdca3d..491d5f8 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -3189,6 +3189,26 @@ h1#agenda-title { margin: 5px 0px; } +#loading-dialog .loading-message { + height: 32px; + width: 32px; + left: 209px; + bottom: 5px; + position: absolute; + display: block; + background: transparent url(/images/loading-dark.gif) center center no-repeat; +} + +/* hide the close x on the loading screen */ +.controller-invite .ui-dialog-titlebar-close { + display: none; +} + +#hotmail_username_tip { + color: red; + margin-top: 10px; +} + /* ==> public/stylesheets/controller_manage_products.css <== */ #category_form { diff --git a/script/delayed_job b/script/delayed_job index c26a64f..c6137a1 100755 --- a/script/delayed_job +++ b/script/delayed_job @@ -6,28 +6,9 @@ # The role of this script is to just start/stop the daemon, write a PID file, # etc. The actual feed update logic is DelayedJob plugin. +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment')) require 'daemons' +require 'delayed/command' -NOOSFERO_ROOT = File.expand_path(File.dirname(__FILE__) + '/../') - -options = { - :dir_mode => :normal, - :dir => File.dirname(__FILE__) + '/../tmp/pids', - :multiple => false, - :backtrace => true, - :monitor => true, -} - -Daemons.run_proc('job_runner', options) do - if ARGV.include?('--') - ARGV.slice! 0..ARGV.index('--') - else - ARGV.clear - end - - Dir.chdir NOOSFERO_ROOT - RAILS_ENV = ARGV.first || ENV['RAILS_ENV'] || 'development' - require NOOSFERO_ROOT + '/config/environment' - - Delayed::Worker.new.start -end +ENV['RAILS_ENV'] ||= "production" +Delayed::Command.new(ARGV).daemonize diff --git a/script/production b/script/production index 9f93821..c494804 100755 --- a/script/production +++ b/script/production @@ -20,14 +20,14 @@ do_start() { clear_cache ./script/ferret_server -e $RAILS_ENV start ./script/feed-updater start - ./script/delayed_job start +# ./script/delayed_job start -n 4 mongrel_rails cluster::start } do_stop() { mongrel_rails cluster::stop ./script/delayed_job stop - ./script/feed-updater stop +# ./script/feed-updater stop ./script/ferret_server -e $RAILS_ENV stop } diff --git a/test/functional/invite_controller_test.rb b/test/functional/invite_controller_test.rb index 939a358..0077478 100644 --- a/test/functional/invite_controller_test.rb +++ b/test/functional/invite_controller_test.rb @@ -11,9 +11,10 @@ class InviteControllerTest < ActionController::TestCase attr_accessor :profile, :friend, :community should 'add manually invitation of an added address with friend object on a queue and process it later' do + contact_list = ContactList.create assert_difference Delayed::Job, :count, 1 do - post :friends, :profile => profile.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: ", :step => 2 - assert_redirected_to :controller => 'friends' + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: ", :contact_list => contact_list.id + assert_redirected_to :controller => 'profile', :action => 'friends' end assert_difference InviteFriend, :count, 1 do @@ -22,9 +23,10 @@ class InviteControllerTest < ActionController::TestCase end should 'add manually invitation of an added address with only email on a queue and process it later' do + contact_list = ContactList.create assert_difference Delayed::Job, :count, 1 do - post :friends, :profile => profile.identifier, :manual_import_addresses => "test@test.com", :import_from => "manual", :mail_template => "click: ", :step => 2 - assert_redirected_to :controller => 'friends' + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "test@test.com", :import_from => "manual", :mail_template => "click: ", :contact_list => contact_list.id + assert_redirected_to :controller => 'profile', :action => 'friends' end assert_difference InviteFriend, :count, 1 do @@ -33,9 +35,10 @@ class InviteControllerTest < ActionController::TestCase end should 'add manually invitation of an added address with email and other format on a queue and process it later' do + contact_list = ContactList.create assert_difference Delayed::Job, :count, 1 do - post :friends, :profile => profile.identifier, :manual_import_addresses => "test@test.cz.com", :import_from => "manual", :mail_template => "click: ", :step => 2 - assert_redirected_to :controller => 'friends' + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "test@test.cz.com", :import_from => "manual", :mail_template => "click: ", :contact_list => contact_list.id + assert_redirected_to :controller => 'profile', :action => 'friends' end assert_difference InviteFriend, :count, 1 do @@ -44,9 +47,10 @@ class InviteControllerTest < ActionController::TestCase end should 'add manually invitation of more than one added address on a queue and process it later' do + contact_list = ContactList.create assert_difference Delayed::Job, :count, 1 do - post :friends, :profile => profile.identifier, :manual_import_addresses => "Some Friend \r\notherperson@bleble.net\r\n", :import_from => "manual", :mail_template => "click: ", :step => 2 - assert_redirected_to :controller => 'friends' + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "Some Friend \r\notherperson@bleble.net\r\n", :import_from => "manual", :mail_template => "click: ", :contact_list => contact_list.id + assert_redirected_to :controller => 'profile', :action => 'friends' end assert_difference InviteFriend, :count, 2 do @@ -55,9 +59,10 @@ class InviteControllerTest < ActionController::TestCase end should 'add manually invitation of an added address with name and e-mail on a queue and process it later' do + contact_list = ContactList.create assert_difference Delayed::Job, :count, 1 do - post :friends, :profile => profile.identifier, :manual_import_addresses => "Test Name ", :import_from => "manual", :mail_template => "click: ", :step => 2 - assert_redirected_to :controller => 'friends' + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "Test Name ", :import_from => "manual", :mail_template => "click: ", :contact_list => contact_list.id + assert_redirected_to :controller => 'profile', :action => 'friends' end assert_difference InviteFriend, :count, 1 do @@ -66,9 +71,10 @@ class InviteControllerTest < ActionController::TestCase end should 'add invitation of yourself on a queue and not process it later' do + contact_list = ContactList.create assert_difference Delayed::Job, :count, 1 do - post :friends, :profile => profile.identifier, :manual_import_addresses => "#{profile.name} <#{profile.user.email}>", :import_from => "manual", :mail_template => "click: ", :step => 2 - assert_redirected_to :controller => 'friends' + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "#{profile.name} <#{profile.user.email}>", :import_from => "manual", :mail_template => "click: ", :contact_list => contact_list.id + assert_redirected_to :controller => 'profile', :action => 'friends' end assert_no_difference InviteFriend, :count do @@ -80,9 +86,10 @@ class InviteControllerTest < ActionController::TestCase friend = create_user('testfriend', :email => 'friend@noosfero.org') friend.person.add_friend(profile) + contact_list = ContactList.create assert_difference Delayed::Job, :count, 1 do - post :friends, :profile => profile.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: ", :step => 2 - assert_redirected_to :controller => 'friends' + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: ", :contact_list => contact_list.id + assert_redirected_to :controller => 'profile', :action => 'friends' end assert_no_difference InviteFriend, :count do @@ -91,42 +98,131 @@ class InviteControllerTest < ActionController::TestCase end should 'display invitation page' do - get :friends, :profile => profile.identifier + get :select_address_book, :profile => profile.identifier assert_response :success assert_tag :tag => 'h1', :content => 'Invite your friends' end should 'get mail template to invite members' do community.add_admin(profile) - get :friends, :profile => community.identifier + contact_list = ContactList.create + get :select_friends, :profile => community.identifier, :contact_list => contact_list.id assert_equal InviteMember.mail_template, assigns(:mail_template) end should 'get mail template to invite friends' do community.add_admin(profile) - get :friends, :profile => profile.identifier + contact_list = ContactList.create + get :select_friends, :profile => profile.identifier, :contact_list => contact_list.id assert_equal InviteFriend.mail_template, assigns(:mail_template) end - should 'deny if user has no rights to invite members' do - get :friends, :profile => community.identifier + should 'deny select_address_book f user has no rights to invite members' do + get :select_address_book, :profile => community.identifier assert_response 403 # forbidden end - should 'deny access when trying to invite friends to another user' do - get :friends, :profile => friend.identifier + should 'deny select_friends if user has no rights to invite members' do + get :select_friends, :profile => community.identifier assert_response 403 # forbidden end - should 'redirect to friends after invitation if profile is a person' do - post :friends, :profile => profile.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: ", :step => 2 - assert_redirected_to :controller => 'friends' + should 'deny select_address_book access when trying to invite friends to another user' do + get :select_address_book, :profile => friend.identifier + assert_response 403 # forbidden + end + + should 'deny select_friends access when trying to invite friends to another user' do + get :select_address_book, :profile => friend.identifier + assert_response 403 # forbidden + end + + should 'redirect to profile after invitation if profile is a person' do + contact_list = ContactList.create + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: ", :contact_list => contact_list.id + assert_redirected_to :controller => 'profile', :action => 'friends' end - should 'redirect to friends after invitation if profile is not a person' do + should 'redirect to profile after invitation if profile is not a person' do community.add_admin(profile) - post :friends, :profile => community.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: ", :step => 2 - assert_redirected_to :controller => 'profile_members' + contact_list = ContactList.create + post :select_friends, :profile => community.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: ", :contact_list => contact_list.id + assert_redirected_to :controller => 'profile', :action => 'members' + end + + should 'create a job to get emails after choose address book' do + community.add_admin(profile) + contact_list = ContactList.create + assert_difference Delayed::Job, :count, 1 do + post :select_address_book, :profile => community.identifier, :contact_list => contact_list.id, :import_from => 'gmail' + assert_redirected_to :action => 'select_friends' + end + end + + should 'destroy contact_list after invitation when import is manual' do + contact_list = ContactList.create + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :mail_template => "click: ", :contact_list => contact_list.id + + assert ContactList.exists?(contact_list.id) + Delayed::Worker.new.work_off + assert !ContactList.exists?(contact_list.id) + end + + should 'destroy contact_list after invitation when import is not manual' do + contact_list = ContactList.create + post :select_friends, :profile => profile.identifier, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "not_manual", :mail_template => "click: ", :contact_list => contact_list.id + + assert ContactList.exists?(contact_list.id) + Delayed::Worker.new.work_off + assert !ContactList.exists?(contact_list.id) + end + + should 'return empty hash as invitation data if contact list was not fetched' do + contact_list = ContactList.create + get :invitation_data, :profile => profile.identifier, :contact_list => contact_list.id + + assert_equal 'application/javascript', @response.content_type + assert_equal '{}', @response.body + end + + should 'return hash as invitation data if contact list was fetched' do + contact_list = ContactList.create(:fetched => true) + get :invitation_data, :profile => profile.identifier, :contact_list => contact_list.id + + assert_equal 'application/javascript', @response.content_type + assert_equal "{\"fetched\": true, \"contact_list\": #{contact_list.id}, \"error\": null}", @response.body + end + + should 'render empty list of contacts' do + contact_list = ContactList.create(:fetched => true) + get :add_contact_list, :profile => profile.identifier, :contact_list => contact_list.id + + assert_response :success + assert_template '_contact_list' + assert_no_tag(:tag => 'input', :attributes => { :type => 'checkbox', :name => 'webmail_import_addresses[]'}) + end + + should 'render list of contacts' do + contact_list = ContactList.create(:fetched => true, :list => ['email1@noosfero.org', 'email2@noosfero.org']) + get :add_contact_list, :profile => profile.identifier, :contact_list => contact_list.id + + assert_response :success + assert_template '_contact_list' + + i = 0 + contact_list.list.each do |contact| + i += 1 + assert_tag(:tag => 'input', :attributes => { :type => 'checkbox', :name => 'webmail_import_addresses[]', :id => "contacts_to_invite_#{i}", :value => contact[2]}) + end + end + + should 'destroy contact_list when cancel_fetching_emails' do + contact_list = ContactList.create + + assert_difference ContactList, :count, -1 do + get :cancel_fetching_emails, :profile => profile.identifier, :contact_list => contact_list.id + end + assert_redirected_to :action => 'select_address_book' end end diff --git a/test/unit/contact_list_test.rb b/test/unit/contact_list_test.rb new file mode 100644 index 0000000..9ec8a64 --- /dev/null +++ b/test/unit/contact_list_test.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class ContactListTest < ActiveSupport::TestCase + + should 'have list as an array' do + assert_equal [], ContactList.create.list + end + + should 'display list' do + contact_list = ContactList.create(:list => ['email1@noosfero.org', 'email2@noosfero.org']) + + assert_equal ['email1@noosfero.org', 'email2@noosfero.org'], contact_list.list + end + + should 'return empty hash if contact list was not fetched' do + contact_list = ContactList.create + assert_equal({}, contact_list.data) + end + + should 'return hash if contact list was fetched' do + contact_list = ContactList.create(:fetched => true) + assert_equal({"fetched" => true, "contact_list" => contact_list.id, "error" => contact_list.error_fetching}, contact_list.data) + end + + should 'update fetched and error_fetching when register auth error' do + contact_list = ContactList.create + assert_equal({}, contact_list.data) + + contact_list.register_error + 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) + end + + should 'update fetched and error_fetching when register error' do + contact_list = ContactList.create + assert_equal({}, contact_list.data) + + contact_list.register_auth_error + 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) + end + +end diff --git a/test/unit/get_email_contacts_job_test.rb b/test/unit/get_email_contacts_job_test.rb new file mode 100644 index 0000000..6c833b8 --- /dev/null +++ b/test/unit/get_email_contacts_job_test.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class GetEmailContactsJobTest < ActiveSupport::TestCase + + should 'register error' do + contact_list = ContactList.create + Invitation.expects(:get_contacts).with('from-email', 'mylogin', 'mypassword', contact_list.id).raises(Exception.new("crash")) + + job = GetEmailContactsJob.new('from-email', 'mylogin', 'mypassword', contact_list.id) + job.perform + + assert ContactList.find(contact_list).fetched + assert_equal 'There was an error while looking for your contact list. Please, try again', ContactList.find(contact_list).error_fetching + end + + should 'register auth error' do + contact_list = ContactList.create + Invitation.expects(:get_contacts).with('from-email', 'mylogin', 'wrongpassword', contact_list.id).raises(Contacts::AuthenticationError) + + job = GetEmailContactsJob.new('from-email', 'mylogin', 'wrongpassword', contact_list.id) + job.perform + + assert ContactList.find(contact_list).fetched + assert_equal 'There was an error while authenticating. Did you enter correct login and password?', ContactList.find(contact_list).error_fetching + end + +end diff --git a/test/unit/invitation_test.rb b/test/unit/invitation_test.rb index 5f9499c..9e3f9a7 100644 --- a/test/unit/invitation_test.rb +++ b/test/unit/invitation_test.rb @@ -26,8 +26,9 @@ class InvitationTest < ActiveSupport::TestCase end should 'raises when try get contacts from unknown source' do + contact_list = ContactList.create assert_raise NotImplementedError do - Invitation.get_contacts('ze', 'ze12', 'bli-mail') + Invitation.get_contacts('ze', 'ze12', 'bli-mail', contact_list.id) end end @@ -71,4 +72,29 @@ class InvitationTest < ActiveSupport::TestCase end end + should 'add url on message if user removed it' do + person = create_user('testuser1').person + friend = create_user('testuser2').person + invitation = Invitation.create!( + :person => person, + :friend => friend, + :message => 'Hi , is inviting you!' + ) + assert_equal "Hi , is inviting you!#{invitation.message_to_accept_invitation}", invitation.message + end + + should 'do nothing with message if user added url' do + person = create_user('testuser1').person + friend = create_user('testuser2').person + invitation = Invitation.create!( + :person => person, + :friend => friend, + :message => 'Hi , is inviting you to be his friend on !' + ) + assert_equal "Hi , is inviting you to be his friend on !", invitation.message + end + + should 'have a message with url' do + assert_equal "

To accept invitation, please follow this link:

", Invitation.new.message_to_accept_invitation + end end diff --git a/test/unit/invite_friend_test.rb b/test/unit/invite_friend_test.rb index 7295305..9ea9b21 100644 --- a/test/unit/invite_friend_test.rb +++ b/test/unit/invite_friend_test.rb @@ -70,21 +70,6 @@ class InviteFriendTest < ActiveSupport::TestCase ok('must validate with no target') { !task.errors.invalid?(:target_id) } end - should 'require message with tag if no target given' do - task = InviteFriend.new - task.valid? - - ok('must not validate with no message') { task.errors.invalid?(:message) } - - task.message = 'a simple message' - task.valid? - ok('must not validate with no tag in message') { task.errors.invalid?(:message) } - - task.message = 'a simple message with ' - task.valid? - ok('must validate when message is given with tag') { !task.errors.invalid?(:message)} - end - should 'dont require message if target given (person being invited)' do task = InviteFriend.new(:target => create_user('testuser2').person) task.valid? -- libgit2 0.21.2