Commit ce257d5c901fc21a4975f16ee01f95479e0f3157

Authored by Joenio Costa
2 parents 1ec026e9 26e5b3d6

Merge branch 'force_show_email' into 'master'

Adds required email moderation option

- Confirmation modal when joining community where user's email is required.
- Moderation option to require email in community control panel.
- Adds task footer support.
    - Implemented for add_member task.   
        - Changes the e-mail of the requestor to appear on the task footer.

See merge request !882
app/controllers/public/profile_controller.rb
@@ -86,8 +86,16 @@ class ProfileController < PublicController @@ -86,8 +86,16 @@ class ProfileController < PublicController
86 @articles = profile.top_level_articles.includes([:profile, :parent]) 86 @articles = profile.top_level_articles.includes([:profile, :parent])
87 end 87 end
88 88
  89 + def join_modal
  90 + profile.add_member(user)
  91 + session[:notice] = _('%s administrator still needs to accept you as member.') % profile.name
  92 + redirect_to :action => :index
  93 + end
  94 +
89 def join 95 def join
90 if !user.memberships.include?(profile) 96 if !user.memberships.include?(profile)
  97 + return if profile.community? && show_confirmation_modal?(profile)
  98 +
91 profile.add_member(user) 99 profile.add_member(user)
92 if !profile.members.include?(user) 100 if !profile.members.include?(user)
93 render :text => {:message => _('%s administrator still needs to accept you as member.') % profile.name}.to_json 101 render :text => {:message => _('%s administrator still needs to accept you as member.') % profile.name}.to_json
app/helpers/application_helper.rb
@@ -54,6 +54,8 @@ module ApplicationHelper @@ -54,6 +54,8 @@ module ApplicationHelper
54 54
55 include TaskHelper 55 include TaskHelper
56 56
  57 + include MembershipsHelper
  58 +
57 def locale 59 def locale
58 (@page && !@page.language.blank?) ? @page.language : FastGettext.locale 60 (@page && !@page.language.blank?) ? @page.language : FastGettext.locale
59 end 61 end
@@ -984,11 +986,11 @@ module ApplicationHelper @@ -984,11 +986,11 @@ module ApplicationHelper
984 986
985 def task_information(task) 987 def task_information(task)
986 values = {} 988 values = {}
  989 + values.merge!(task.information[:variables]) if task.information[:variables]
987 values.merge!({:requestor => link_to(task.requestor.name, task.requestor.url)}) if task.requestor 990 values.merge!({:requestor => link_to(task.requestor.name, task.requestor.url)}) if task.requestor
988 values.merge!({:subject => content_tag('span', task.subject, :class=>'task_target')}) if task.subject 991 values.merge!({:subject => content_tag('span', task.subject, :class=>'task_target')}) if task.subject
989 values.merge!({:linked_subject => link_to(content_tag('span', task.linked_subject[:text], :class => 'task_target'), task.linked_subject[:url])}) if task.linked_subject 992 values.merge!({:linked_subject => link_to(content_tag('span', task.linked_subject[:text], :class => 'task_target'), task.linked_subject[:url])}) if task.linked_subject
990 - values.merge!(task.information[:variables]) if task.information[:variables]  
991 - task.information[:message] % values 993 + (task.information[:message] % values).html_safe
992 end 994 end
993 995
994 def add_zoom_to_article_images 996 def add_zoom_to_article_images
app/helpers/memberships_helper.rb
1 module MembershipsHelper 1 module MembershipsHelper
  2 +
  3 + def join_community_button options={:logged => false}
  4 + url = options[:logged] ? profile.join_url : profile.join_not_logged_url
  5 +
  6 + if show_confirmation_modal? profile
  7 + modal_button :add, _('Join this community'), url, class: 'join-community'
  8 + else
  9 + button :add, _('Join this community'), url, class: 'join-community'
  10 + end
  11 + end
  12 +
  13 + def show_confirmation_modal? profile
  14 + profile.requires_email? && current_person && !current_person.public_fields.include?("email")
  15 + end
  16 +
2 end 17 end
app/helpers/profile_image_helper.rb
@@ -61,6 +61,8 @@ module ProfileImageHelper @@ -61,6 +61,8 @@ module ProfileImageHelper
61 image_tag(profile_icon(profile, size), opt ) 61 image_tag(profile_icon(profile, size), opt )
62 end 62 end
63 63
  64 + include MembershipsHelper
  65 +
64 def links_for_balloon(profile) 66 def links_for_balloon(profile)
65 if environment.enabled?(:show_balloon_with_profile_links_when_clicked) 67 if environment.enabled?(:show_balloon_with_profile_links_when_clicked)
66 if profile.kind_of?(Person) 68 if profile.kind_of?(Person)
@@ -76,7 +78,7 @@ module ProfileImageHelper @@ -76,7 +78,7 @@ module ProfileImageHelper
76 {_('Wall') => {:href => url_for(profile.public_profile_url)}}, 78 {_('Wall') => {:href => url_for(profile.public_profile_url)}},
77 {_('Members') => {:href => url_for(:controller => :profile, :action => :members, :profile => profile.identifier)}}, 79 {_('Members') => {:href => url_for(:controller => :profile, :action => :members, :profile => profile.identifier)}},
78 {_('Agenda') => {:href => url_for(:controller => :profile, :action => :events, :profile => profile.identifier)}}, 80 {_('Agenda') => {:href => url_for(:controller => :profile, :action => :events, :profile => profile.identifier)}},
79 - {_('Join') => {:href => url_for(profile.join_url), :class => 'join-community', :style => 'display: none'}}, 81 + {_('Join') => {:href => url_for(profile.join_url), :class => 'join-community'+ (show_confirmation_modal?(profile) ? ' modal-toggle' : '') , :style => 'display: none'}},
80 {_('Leave community') => {:href => url_for(profile.leave_url), :class => 'leave-community', :style => 'display: none'}}, 82 {_('Leave community') => {:href => url_for(profile.leave_url), :class => 'leave-community', :style => 'display: none'}},
81 {_('Send an e-mail') => {:href => url_for(:profile => profile.identifier, :controller => 'contact', :action => 'new'), :class => 'send-an-email', :style => 'display: none'}} 83 {_('Send an e-mail') => {:href => url_for(:profile => profile.identifier, :controller => 'contact', :action => 'new'), :class => 'send-an-email', :style => 'display: none'}}
82 ] 84 ]
app/models/add_member.rb
@@ -29,16 +29,18 @@ class AddMember < Task @@ -29,16 +29,18 @@ class AddMember < Task
29 end 29 end
30 30
31 def information 31 def information
32 - requestor_email = " (#{requestor.email})" if requestor.may_display_field_to?("email")  
33 -  
34 - {:message => _("%{requestor}%{requestor_email} wants to be a member of '%{organization}'."),  
35 - variables: {requestor: requestor.name, requestor_email: requestor_email, organization: organization.name}} 32 + {:message => _("%{requestor} wants to be a member of '%{target}'."),
  33 + variables: {requestor: requestor.name, target: target.name}}
36 end 34 end
37 35
38 def accept_details 36 def accept_details
39 true 37 true
40 end 38 end
41 39
  40 + def footer
  41 + true
  42 + end
  43 +
42 def icon 44 def icon
43 {:type => :profile_image, :profile => requestor, :url => requestor.url} 45 {:type => :profile_image, :profile => requestor, :url => requestor.url}
44 end 46 end
@@ -63,4 +65,15 @@ class AddMember < Task @@ -63,4 +65,15 @@ class AddMember < Task
63 suggestion.disable if suggestion 65 suggestion.disable if suggestion
64 end 66 end
65 67
  68 + def task_finished_message
  69 + _("You have been accepted at \"%{target}\" with the profile \"%{requestor}\"") %
  70 + {:target => self.target.name,
  71 + :requestor => self.requestor.name}
  72 + end
  73 +
  74 + def task_cancelled_message
  75 + _("Your request to enter community \"%{target} with the profile \"%{requestor}\" was not accepted. Please contact any profile admin from %{url} for more information.") %
  76 + {:target => self.target.name, :url => self.target.url,
  77 + :requestor => self.requestor.name}
  78 + end
66 end 79 end
app/models/community.rb
@@ -2,6 +2,7 @@ class Community < Organization @@ -2,6 +2,7 @@ class Community < Organization
2 2
3 attr_accessible :accessor_id, :accessor_type, :role_id, :resource_id, :resource_type 3 attr_accessible :accessor_id, :accessor_type, :role_id, :resource_id, :resource_type
4 attr_accessible :address_reference, :district, :tag_list, :language, :description 4 attr_accessible :address_reference, :district, :tag_list, :language, :description
  5 + attr_accessible :requires_email
5 after_destroy :check_invite_member_for_destroy 6 after_destroy :check_invite_member_for_destroy
6 7
7 def self.type_name 8 def self.type_name
@@ -12,6 +13,9 @@ class Community < Organization @@ -12,6 +13,9 @@ class Community < Organization
12 N_('Language') 13 N_('Language')
13 14
14 settings_items :language 15 settings_items :language
  16 + settings_items :requires_email, :type => :boolean
  17 +
  18 + alias_method :requires_email?, :requires_email
15 19
16 extend SetProfileRegionFromCityState::ClassMethods 20 extend SetProfileRegionFromCityState::ClassMethods
17 set_profile_region_from_city_state 21 set_profile_region_from_city_state
app/models/task.rb
@@ -190,6 +190,10 @@ class Task < ApplicationRecord @@ -190,6 +190,10 @@ class Task < ApplicationRecord
190 false 190 false
191 end 191 end
192 192
  193 + def footer
  194 + false
  195 + end
  196 +
193 def icon 197 def icon
194 {:type => :defined_image, :src => "/images/icons-app/user-minor.png", :name => requestor.name, :url => requestor.url} 198 {:type => :defined_image, :src => "/images/icons-app/user-minor.png", :name => requestor.name, :url => requestor.url}
195 end 199 end
app/views/blocks/profile_info_actions/_join_leave_community.html.erb
@@ -7,15 +7,12 @@ @@ -7,15 +7,12 @@
7 <%= button :delete, content_tag('span', _('Leave community')), profile.leave_url, 7 <%= button :delete, content_tag('span', _('Leave community')), profile.leave_url,
8 class: 'leave-community', 8 class: 'leave-community',
9 style: 'position: relative;' %> 9 style: 'position: relative;' %>
10 - <%= button :add, content_tag('span', _('Join this community')), profile.join_url,  
11 - class: 'join-community',  
12 - style: 'position: relative; display: none;' %>  
13 <% else %> 10 <% else %>
14 - <%= button :add, _('Join this community'), profile.join_url, class: 'join-community' %> 11 + <%= join_community_button({:logged => true}) %>
15 <% end %> 12 <% end %>
16 <% end %> 13 <% end %>
17 <% else %> 14 <% else %>
18 - <%= button :add, _('Join this community'), profile.join_not_logged_url %> 15 + <%= join_community_button %>
19 <% end %> 16 <% end %>
20 </div> 17 </div>
21 18
app/views/profile/_private_profile.html.erb
@@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
7 7
8 <% button_bar do %> 8 <% button_bar do %>
9 <% if @action == :join && logged_in? %> 9 <% if @action == :join && logged_in? %>
10 - <%= button(:add, content_tag('span', _('Join')), profile.join_url, :class => 'join-community', :title => _("Join community"), :style => 'position: relative;') %> 10 + <%= join_community_button({:logged => true}) %>
11 <% end %> 11 <% end %>
12 <% if @action == :add_friend && logged_in? && !user.already_request_friendship?(profile) %> 12 <% if @action == :add_friend && logged_in? && !user.already_request_friendship?(profile) %>
13 <%= button(:add, content_tag('span', _('Add friend')), profile.add_url, :class => 'add-friend', :title => _("Add friend"), :style => 'position: relative;') %> 13 <%= button(:add, content_tag('span', _('Add friend')), profile.add_url, :class => 'add-friend', :title => _("Add friend"), :style => 'position: relative;') %>
app/views/profile/join.html.erb
1 -<h1><%= _('Joining %s') % profile.name %></h1> 1 +<div class="join-community-confirmation">
2 2
3 -<p>  
4 -<%= _('Are you sure you want to join %s?') % profile.name %>  
5 -</p> 3 + <h1><%= _('To join %s, you must:') % profile.name %></h1>
6 4
7 -<%= form_tag do %>  
8 - <%= hidden_field_tag('back_to', @back_to) %>  
9 - <%= hidden_field_tag(:confirmation, 1) %>  
10 - <%= submit_button(:ok, _("Yes, I want to join.") % profile.name) %>  
11 - <% if logged_in? && request.xhr? %>  
12 - <%= modal_close_button _("No, I don't want") %>  
13 - <% else %>  
14 - <%= button(:cancel, _("No, I don't want."), profile.url) %> 5 + <p>
  6 + <%= _("Authorize the visibility of your email address to the community administrator.") %>
  7 + </p>
  8 +
  9 + <%= form_tag url_for({:action => :join_modal, :controller => :profile}) do %>
  10 + <%= hidden_field_tag('back_to', @back_to) %>
  11 + <%= submit_button(:ok, _("Authorize")) %>
  12 + <%= modal_close_button _("Cancel") %>
15 <% end %> 13 <% end %>
16 -<% end %> 14 +
  15 +</div>
  16 +
app/views/profile_editor/_moderation.html.erb
@@ -9,7 +9,6 @@ @@ -9,7 +9,6 @@
9 <%= _('Send administrator Email for every task') %> 9 <%= _('Send administrator Email for every task') %>
10 </div> 10 </div>
11 </div> 11 </div>
12 -  
13 <div style='margin-bottom: 1em'> 12 <div style='margin-bottom: 1em'>
14 <h4><%= _('Invitation moderation:')%></h4> 13 <h4><%= _('Invitation moderation:')%></h4>
15 </div> 14 </div>
@@ -36,6 +35,12 @@ @@ -36,6 +35,12 @@
36 <div style='margin-left: 30px'> 35 <div style='margin-left: 30px'>
37 <%= _('<strong>Before</strong> joining this group (a moderator has to accept the member in pending request before member can access the intranet and/or the website).').html_safe %> 36 <%= _('<strong>Before</strong> joining this group (a moderator has to accept the member in pending request before member can access the intranet and/or the website).').html_safe %>
38 </div> 37 </div>
  38 + <div id = "requires_email_option" style="margin-left: 30px; margin-top: 10px; margin-bottom: 15px;<%=" display: none;" unless profile.closed? %>">
  39 + <%= check_box(:profile_data, :requires_email, :style => 'float: left') %>
  40 + <div style='margin-left: 30px'>
  41 + <%= _('New members must allow email visibility to the profile admin') %>
  42 + </div>
  43 + </div>
39 </div> 44 </div>
40 <div> 45 <div>
41 <%= radio_button 'profile_data', 'closed', 'false', :style => 'float: left' %> 46 <%= radio_button 'profile_data', 'closed', 'false', :style => 'float: left' %>
app/views/tasks/_add_member_footer.html.erb 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +<% if (task.organization.requires_email || task.requestor.may_display_field_to?("email")) %>
  2 + <div>
  3 + Email:
  4 + <span id="task_email"> <%=task.requestor.email %> </span>
  5 + </div>
  6 +<% end %>
  7 +
app/views/tasks/_task.html.erb
@@ -70,4 +70,10 @@ @@ -70,4 +70,10 @@
70 <% end %> 70 <% end %>
71 <% end %> 71 <% end %>
72 72
  73 + <% if task.footer %>
  74 + <div id="task-footer-<%=task.id%>">
  75 + <%= render :partial => partial_for_class(task.class, nil, :footer), :locals => {:task => task} %>
  76 + </div>
  77 + <% end %>
  78 +
73 </div><!-- class="task_box" --> 79 </div><!-- class="task_box" -->
public/designs/themes/base/style.scss
@@ -1555,3 +1555,21 @@ table#recaptcha_table tr:hover td { @@ -1555,3 +1555,21 @@ table#recaptcha_table tr:hover td {
1555 clear: both; 1555 clear: both;
1556 } 1556 }
1557 1557
  1558 +
  1559 +/*************************** join community confirmation ********************************/
  1560 +
  1561 +.join-community-confirmation h1 {
  1562 + font-variant: small-caps;
  1563 + font-size: 20px;
  1564 + color: #555753;
  1565 + text-align: left;
  1566 +}
  1567 +
  1568 +.join-community-confirmation {
  1569 + padding: 5px 20px 0px 20px;
  1570 +}
  1571 +
  1572 +.join-community-confirmation input.button.with-text {
  1573 + padding-right: 4px;
  1574 +}
  1575 +
public/javascripts/add-and-join.js
@@ -18,9 +18,11 @@ jQuery(function($) { @@ -18,9 +18,11 @@ jQuery(function($) {
18 }) 18 })
19 19
20 $(".join-community").live('click', function(){ 20 $(".join-community").live('click', function(){
  21 + $('#cboxClose').remove();
21 clicked = $(this); 22 clicked = $(this);
22 url = clicked.attr("href"); 23 url = clicked.attr("href");
23 - loading_for_button(this); 24 + if (!clicked.hasClass('modal-toggle'))
  25 + loading_for_button(this);
24 $.post(url, function(data){ 26 $.post(url, function(data){
25 clicked.fadeOut(function(){ 27 clicked.fadeOut(function(){
26 clicked.css("display","none"); 28 clicked.css("display","none");
public/javascripts/profile_editor.js
@@ -23,4 +23,14 @@ @@ -23,4 +23,14 @@
23 }); 23 });
24 24
25 }); 25 });
  26 +
  27 + $("#profile_data_closed_false").click(function(){
  28 + $("#requires_email_option").prop("checked",false);
  29 + $("#requires_email_option").hide();
  30 + });
  31 +
  32 + $("#profile_data_closed_true").click(function(){
  33 + $("#requires_email_option").show();
  34 + });
  35 +
26 })(jQuery); 36 })(jQuery);
test/functional/profile_controller_test.rb
@@ -3,6 +3,8 @@ require &#39;profile_controller&#39; @@ -3,6 +3,8 @@ require &#39;profile_controller&#39;
3 3
4 class ProfileControllerTest < ActionController::TestCase 4 class ProfileControllerTest < ActionController::TestCase
5 5
  6 + include MembershipsHelper
  7 +
6 self.default_params = {profile: 'testuser'} 8 self.default_params = {profile: 'testuser'}
7 def setup 9 def setup
8 @profile = create_user('testuser').person 10 @profile = create_user('testuser').person
@@ -384,6 +386,61 @@ class ProfileControllerTest &lt; ActionController::TestCase @@ -384,6 +386,61 @@ class ProfileControllerTest &lt; ActionController::TestCase
384 assert_redirected_to :controller => 'account', :action => 'login' 386 assert_redirected_to :controller => 'account', :action => 'login'
385 end 387 end
386 388
  389 + should 'show regular join button for person with public email' do
  390 + community = Community.create!(:name => 'my test community', :closed => true, :requires_email => true)
  391 + Person.any_instance.stubs(:public_fields).returns(["email"])
  392 + login_as(@profile.identifier)
  393 +
  394 + get :index, :profile => community.identifier
  395 + assert_no_tag :tag => 'a', :attributes => { :class => /modal-toggle join-community/ }
  396 + end
  397 +
  398 + should 'show join modal for person with private email' do
  399 + community = Community.create!(:name => 'my test community', :closed => true, :requires_email => true)
  400 + Person.any_instance.stubs(:public_fields).returns([])
  401 + login_as(@profile.identifier)
  402 +
  403 + get :index, :profile => community.identifier
  404 + assert_tag :tag => 'a', :attributes => { :class => /modal-toggle join-community/ }
  405 + end
  406 +
  407 + should 'show regular join button for community without email visibility requirement' do
  408 + community = Community.create!(:name => 'my test community', :closed => true, :requires_email => false)
  409 + Person.any_instance.stubs(:public_fields).returns([])
  410 + login_as(@profile.identifier)
  411 +
  412 + get :index, :profile => community.identifier
  413 + assert_no_tag :tag => 'a', :attributes => { :class => /modal-toggle join-community/ }
  414 + end
  415 +
  416 + should 'show regular join button for community without email visibility requirement and person with public email' do
  417 + community = Community.create!(:name => 'my test community', :closed => true, :requires_email => false)
  418 + Person.any_instance.stubs(:public_fields).returns(['email'])
  419 + login_as(@profile.identifier)
  420 +
  421 + get :index, :profile => community.identifier
  422 + assert_no_tag :tag => 'a', :attributes => { :class => /modal-toggle join-community/ }
  423 + end
  424 +
  425 + should 'render join modal for community with email visibility requirement and person with private email' do
  426 + community = Community.create!(:name => 'my test community', :closed => true, :requires_email => true)
  427 + login_as @profile.identifier
  428 + post :join, :profile => community.identifier
  429 + assert_template "join"
  430 + end
  431 +
  432 + should 'create add member task from join-community modal' do
  433 + community = Community.create!(:name => 'my test community', :closed => true, :requires_email => true)
  434 + admin = create_user('community-admin').person
  435 + community.add_admin(admin)
  436 +
  437 + login_as @profile.identifier
  438 + assert_difference 'AddMember.count' do
  439 + post :join_modal, :profile => community.identifier
  440 + end
  441 + assert_redirected_to :action => 'index'
  442 + end
  443 +
387 should 'actually leave profile' do 444 should 'actually leave profile' do
388 community = fast_create(Community) 445 community = fast_create(Community)
389 admin = fast_create(Person) 446 admin = fast_create(Person)
test/unit/add_member_test.rb
@@ -3,7 +3,8 @@ require_relative &quot;../test_helper&quot; @@ -3,7 +3,8 @@ require_relative &quot;../test_helper&quot;
3 class AddMemberTest < ActiveSupport::TestCase 3 class AddMemberTest < ActiveSupport::TestCase
4 4
5 def setup 5 def setup
6 - @person = fast_create(Person) 6 + @user = fast_create(User)
  7 + @person = fast_create(Person,:user_id => @user.id)
7 @community = fast_create(Community) 8 @community = fast_create(Community)
8 end 9 end
9 attr_reader :person, :community 10 attr_reader :person, :community
@@ -63,6 +64,16 @@ class AddMemberTest &lt; ActiveSupport::TestCase @@ -63,6 +64,16 @@ class AddMemberTest &lt; ActiveSupport::TestCase
63 task = AddMember.create!(:person => person, :organization => community) 64 task = AddMember.create!(:person => person, :organization => community)
64 end 65 end
65 66
  67 + should 'send e-mails to requestor' do
  68 + community.update_attribute(:closed, true)
  69 + community.stubs(:notification_emails).returns(["adm@example.com"])
  70 +
  71 + task = AddMember.create!(:person => person, :organization => community)
  72 + assert_difference "ActionMailer::Base.deliveries.size" do
  73 + task.finish
  74 + end
  75 + end
  76 +
66 should 'has permission to manage members' do 77 should 'has permission to manage members' do
67 t = AddMember.new 78 t = AddMember.new
68 assert_equal :manage_memberships, t.permission 79 assert_equal :manage_memberships, t.permission