Commit ce257d5c901fc21a4975f16ee01f95479e0f3157
Exists in
staging
and in
31 other branches
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
Showing
18 changed files
with
190 additions
and
29 deletions
Show diff stats
app/controllers/public/profile_controller.rb
| ... | ... | @@ -86,8 +86,16 @@ class ProfileController < PublicController |
| 86 | 86 | @articles = profile.top_level_articles.includes([:profile, :parent]) |
| 87 | 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 | 95 | def join |
| 90 | 96 | if !user.memberships.include?(profile) |
| 97 | + return if profile.community? && show_confirmation_modal?(profile) | |
| 98 | + | |
| 91 | 99 | profile.add_member(user) |
| 92 | 100 | if !profile.members.include?(user) |
| 93 | 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 | 54 | |
| 55 | 55 | include TaskHelper |
| 56 | 56 | |
| 57 | + include MembershipsHelper | |
| 58 | + | |
| 57 | 59 | def locale |
| 58 | 60 | (@page && !@page.language.blank?) ? @page.language : FastGettext.locale |
| 59 | 61 | end |
| ... | ... | @@ -984,11 +986,11 @@ module ApplicationHelper |
| 984 | 986 | |
| 985 | 987 | def task_information(task) |
| 986 | 988 | values = {} |
| 989 | + values.merge!(task.information[:variables]) if task.information[:variables] | |
| 987 | 990 | values.merge!({:requestor => link_to(task.requestor.name, task.requestor.url)}) if task.requestor |
| 988 | 991 | values.merge!({:subject => content_tag('span', task.subject, :class=>'task_target')}) if task.subject |
| 989 | 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 | 994 | end |
| 993 | 995 | |
| 994 | 996 | def add_zoom_to_article_images | ... | ... |
app/helpers/memberships_helper.rb
| 1 | 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 | 17 | end | ... | ... |
app/helpers/profile_image_helper.rb
| ... | ... | @@ -61,6 +61,8 @@ module ProfileImageHelper |
| 61 | 61 | image_tag(profile_icon(profile, size), opt ) |
| 62 | 62 | end |
| 63 | 63 | |
| 64 | + include MembershipsHelper | |
| 65 | + | |
| 64 | 66 | def links_for_balloon(profile) |
| 65 | 67 | if environment.enabled?(:show_balloon_with_profile_links_when_clicked) |
| 66 | 68 | if profile.kind_of?(Person) |
| ... | ... | @@ -76,7 +78,7 @@ module ProfileImageHelper |
| 76 | 78 | {_('Wall') => {:href => url_for(profile.public_profile_url)}}, |
| 77 | 79 | {_('Members') => {:href => url_for(:controller => :profile, :action => :members, :profile => profile.identifier)}}, |
| 78 | 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 | 82 | {_('Leave community') => {:href => url_for(profile.leave_url), :class => 'leave-community', :style => 'display: none'}}, |
| 81 | 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 | 29 | end |
| 30 | 30 | |
| 31 | 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 | 34 | end |
| 37 | 35 | |
| 38 | 36 | def accept_details |
| 39 | 37 | true |
| 40 | 38 | end |
| 41 | 39 | |
| 40 | + def footer | |
| 41 | + true | |
| 42 | + end | |
| 43 | + | |
| 42 | 44 | def icon |
| 43 | 45 | {:type => :profile_image, :profile => requestor, :url => requestor.url} |
| 44 | 46 | end |
| ... | ... | @@ -63,4 +65,15 @@ class AddMember < Task |
| 63 | 65 | suggestion.disable if suggestion |
| 64 | 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 | 79 | end | ... | ... |
app/models/community.rb
| ... | ... | @@ -2,6 +2,7 @@ class Community < Organization |
| 2 | 2 | |
| 3 | 3 | attr_accessible :accessor_id, :accessor_type, :role_id, :resource_id, :resource_type |
| 4 | 4 | attr_accessible :address_reference, :district, :tag_list, :language, :description |
| 5 | + attr_accessible :requires_email | |
| 5 | 6 | after_destroy :check_invite_member_for_destroy |
| 6 | 7 | |
| 7 | 8 | def self.type_name |
| ... | ... | @@ -12,6 +13,9 @@ class Community < Organization |
| 12 | 13 | N_('Language') |
| 13 | 14 | |
| 14 | 15 | settings_items :language |
| 16 | + settings_items :requires_email, :type => :boolean | |
| 17 | + | |
| 18 | + alias_method :requires_email?, :requires_email | |
| 15 | 19 | |
| 16 | 20 | extend SetProfileRegionFromCityState::ClassMethods |
| 17 | 21 | set_profile_region_from_city_state | ... | ... |
app/models/task.rb
| ... | ... | @@ -190,6 +190,10 @@ class Task < ApplicationRecord |
| 190 | 190 | false |
| 191 | 191 | end |
| 192 | 192 | |
| 193 | + def footer | |
| 194 | + false | |
| 195 | + end | |
| 196 | + | |
| 193 | 197 | def icon |
| 194 | 198 | {:type => :defined_image, :src => "/images/icons-app/user-minor.png", :name => requestor.name, :url => requestor.url} |
| 195 | 199 | end | ... | ... |
app/views/blocks/profile_info_actions/_join_leave_community.html.erb
| ... | ... | @@ -7,15 +7,12 @@ |
| 7 | 7 | <%= button :delete, content_tag('span', _('Leave community')), profile.leave_url, |
| 8 | 8 | class: 'leave-community', |
| 9 | 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 | 10 | <% else %> |
| 14 | - <%= button :add, _('Join this community'), profile.join_url, class: 'join-community' %> | |
| 11 | + <%= join_community_button({:logged => true}) %> | |
| 15 | 12 | <% end %> |
| 16 | 13 | <% end %> |
| 17 | 14 | <% else %> |
| 18 | - <%= button :add, _('Join this community'), profile.join_not_logged_url %> | |
| 15 | + <%= join_community_button %> | |
| 19 | 16 | <% end %> |
| 20 | 17 | </div> |
| 21 | 18 | ... | ... |
app/views/profile/_private_profile.html.erb
| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | |
| 8 | 8 | <% button_bar do %> |
| 9 | 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 | 11 | <% end %> |
| 12 | 12 | <% if @action == :add_friend && logged_in? && !user.already_request_friendship?(profile) %> |
| 13 | 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 | 13 | <% end %> |
| 16 | -<% end %> | |
| 14 | + | |
| 15 | +</div> | |
| 16 | + | ... | ... |
app/views/profile_editor/_moderation.html.erb
| ... | ... | @@ -9,7 +9,6 @@ |
| 9 | 9 | <%= _('Send administrator Email for every task') %> |
| 10 | 10 | </div> |
| 11 | 11 | </div> |
| 12 | - | |
| 13 | 12 | <div style='margin-bottom: 1em'> |
| 14 | 13 | <h4><%= _('Invitation moderation:')%></h4> |
| 15 | 14 | </div> |
| ... | ... | @@ -36,6 +35,12 @@ |
| 36 | 35 | <div style='margin-left: 30px'> |
| 37 | 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 | 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 | 44 | </div> |
| 40 | 45 | <div> |
| 41 | 46 | <%= radio_button 'profile_data', 'closed', 'false', :style => 'float: left' %> | ... | ... |
app/views/tasks/_task.html.erb
| ... | ... | @@ -70,4 +70,10 @@ |
| 70 | 70 | <% end %> |
| 71 | 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 | 79 | </div><!-- class="task_box" --> | ... | ... |
public/designs/themes/base/style.scss
| ... | ... | @@ -1555,3 +1555,21 @@ table#recaptcha_table tr:hover td { |
| 1555 | 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 | 18 | }) |
| 19 | 19 | |
| 20 | 20 | $(".join-community").live('click', function(){ |
| 21 | + $('#cboxClose').remove(); | |
| 21 | 22 | clicked = $(this); |
| 22 | 23 | url = clicked.attr("href"); |
| 23 | - loading_for_button(this); | |
| 24 | + if (!clicked.hasClass('modal-toggle')) | |
| 25 | + loading_for_button(this); | |
| 24 | 26 | $.post(url, function(data){ |
| 25 | 27 | clicked.fadeOut(function(){ |
| 26 | 28 | clicked.css("display","none"); | ... | ... |
public/javascripts/profile_editor.js
| ... | ... | @@ -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 | 36 | })(jQuery); | ... | ... |
test/functional/profile_controller_test.rb
| ... | ... | @@ -3,6 +3,8 @@ require 'profile_controller' |
| 3 | 3 | |
| 4 | 4 | class ProfileControllerTest < ActionController::TestCase |
| 5 | 5 | |
| 6 | + include MembershipsHelper | |
| 7 | + | |
| 6 | 8 | self.default_params = {profile: 'testuser'} |
| 7 | 9 | def setup |
| 8 | 10 | @profile = create_user('testuser').person |
| ... | ... | @@ -384,6 +386,61 @@ class ProfileControllerTest < ActionController::TestCase |
| 384 | 386 | assert_redirected_to :controller => 'account', :action => 'login' |
| 385 | 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 | 444 | should 'actually leave profile' do |
| 388 | 445 | community = fast_create(Community) |
| 389 | 446 | admin = fast_create(Person) | ... | ... |
test/unit/add_member_test.rb
| ... | ... | @@ -3,7 +3,8 @@ require_relative "../test_helper" |
| 3 | 3 | class AddMemberTest < ActiveSupport::TestCase |
| 4 | 4 | |
| 5 | 5 | def setup |
| 6 | - @person = fast_create(Person) | |
| 6 | + @user = fast_create(User) | |
| 7 | + @person = fast_create(Person,:user_id => @user.id) | |
| 7 | 8 | @community = fast_create(Community) |
| 8 | 9 | end |
| 9 | 10 | attr_reader :person, :community |
| ... | ... | @@ -63,6 +64,16 @@ class AddMemberTest < ActiveSupport::TestCase |
| 63 | 64 | task = AddMember.create!(:person => person, :organization => community) |
| 64 | 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 | 77 | should 'has permission to manage members' do |
| 67 | 78 | t = AddMember.new |
| 68 | 79 | assert_equal :manage_memberships, t.permission | ... | ... |