Commit 8d1bd66e7f55683c6ec4a3d451188089d104e022
Committed by
Antonio Terceiro
1 parent
b61c5145
Exists in
master
and in
23 other branches
ActionItem1127: allowing enterprises to add members
* added loading image * added drag and drop * turned unassociate to AJAX * adding members via ajax * added the user finding via ajax
Showing
12 changed files
with
256 additions
and
23 deletions
Show diff stats
app/controllers/my_profile/profile_members_controller.rb
| 1 | class ProfileMembersController < MyProfileController | 1 | class ProfileMembersController < MyProfileController |
| 2 | protect 'manage_memberships', :profile | 2 | protect 'manage_memberships', :profile |
| 3 | + no_design_blocks | ||
| 3 | 4 | ||
| 4 | def index | 5 | def index |
| 5 | @members = profile.members | 6 | @members = profile.members |
| @@ -43,7 +44,7 @@ class ProfileMembersController < MyProfileController | @@ -43,7 +44,7 @@ class ProfileMembersController < MyProfileController | ||
| 43 | else | 44 | else |
| 44 | flash[:notice] = 'Failed to unassociate member' | 45 | flash[:notice] = 'Failed to unassociate member' |
| 45 | end | 46 | end |
| 46 | - redirect_to :aciton => 'index' | 47 | + render :layout => false |
| 47 | end | 48 | end |
| 48 | 49 | ||
| 49 | def unassociate | 50 | def unassociate |
| @@ -56,7 +57,23 @@ class ProfileMembersController < MyProfileController | @@ -56,7 +57,23 @@ class ProfileMembersController < MyProfileController | ||
| 56 | flash[:notice] = 'Failed to unassociate member' | 57 | flash[:notice] = 'Failed to unassociate member' |
| 57 | end | 58 | end |
| 58 | end | 59 | end |
| 59 | - redirect_to :action => 'index' | 60 | + render :layout => false |
| 61 | + end | ||
| 62 | + | ||
| 63 | + def add_members | ||
| 64 | + end | ||
| 65 | + | ||
| 66 | + def add_member | ||
| 67 | + if profile.enterprise? | ||
| 68 | + member = Person.find_by_identifier(params[:id]) | ||
| 69 | + member.define_roles(Profile::Roles.all_roles(environment), profile) | ||
| 70 | + end | ||
| 71 | + render :layout => false | ||
| 72 | + end | ||
| 73 | + | ||
| 74 | + def find_users | ||
| 75 | + @users_found = Person.find_by_contents(params[:query]) | ||
| 76 | + render :layout => false | ||
| 60 | end | 77 | end |
| 61 | 78 | ||
| 62 | end | 79 | end |
| @@ -0,0 +1,24 @@ | @@ -0,0 +1,24 @@ | ||
| 1 | +<h3><%= _('Current Members') %></h3> | ||
| 2 | + | ||
| 3 | +<table> | ||
| 4 | + <tr> | ||
| 5 | + <th><%= _('Member') %></th> | ||
| 6 | + <th><%= _('Actions') %></th> | ||
| 7 | + </tr> | ||
| 8 | + <% profile.members.each do |m| %> | ||
| 9 | + <tr> | ||
| 10 | + <td><%= link_to_profile m.short_name, m.identifier, :title => m.name %> </td> | ||
| 11 | + <td> | ||
| 12 | + <div class="members-buttons-cell"> | ||
| 13 | + <%= button_without_text :edit, _('Edit'), :action => 'change_role', :id => m %> | ||
| 14 | + <%= button_to_remote_without_text :remove, _('Remove'), | ||
| 15 | + :update => 'members-list', | ||
| 16 | + :loading => '$("members-list").addClassName("loading")', | ||
| 17 | + :success => "$('tr-#{m.identifier}').show()", | ||
| 18 | + :complete => '$("members-list").removeClassName("loading")', | ||
| 19 | + :url => {:action => 'unassociate', :id => m} %> | ||
| 20 | + </div> | ||
| 21 | + </td> | ||
| 22 | + </tr> | ||
| 23 | + <% end %> | ||
| 24 | +</table> |
| @@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
| 1 | +<h2><%= _('Add members to %s') % profile.name %></h2> | ||
| 2 | + | ||
| 3 | +<% form_remote_tag :url => {:action => 'find_users', :profile => profile.identifier}, :update => 'users-list', :loading => '$("users-list").addClassName("loading")', :complete => '$("users-list").removeClassName("loading")' do %> | ||
| 4 | + <%= text_field_tag('query') %> | ||
| 5 | + <%= submit_tag(_('Search')) %> | ||
| 6 | +<% end %> | ||
| 7 | + | ||
| 8 | +<%= observe_field('query', :url => {:action => 'find_users', :profile => profile.identifier}, :update => 'users-list', :frequency => 1, :with => 'query', :condition => '$("query").value.length > 2', :loading => '$("users-list").addClassName("loading")', :complete => '$("users-list").removeClassName("loading")') %> | ||
| 9 | + | ||
| 10 | +<div id="users-list"> | ||
| 11 | + <%= render :partial => 'find_users' %> | ||
| 12 | +</div> | ||
| 13 | + | ||
| 14 | +<div id="members-list" class="add-members"> | ||
| 15 | + <%= render :partial => 'members_list' %> | ||
| 16 | +</div> | ||
| 17 | +<%= drop_receiving_element('members-list', | ||
| 18 | + :url => {:action => 'add_member', :profile => profile.identifier}, | ||
| 19 | + :before => '$("tr-" + element.id).hide()', | ||
| 20 | + :loading => '$("members-list").addClassName("loading")', | ||
| 21 | + :update => 'members-list', | ||
| 22 | + :success => '$("tr-" + element.id).hide(); $(element.id).show();', | ||
| 23 | + :complete => '$("members-list").removeClassName("loading")') %> | ||
| 24 | + | ||
| 25 | +<br style="clear:both" /> |
| @@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
| 1 | +<h3> <%= _('Users') %> </h3> | ||
| 2 | +<table> | ||
| 3 | + <tr><th><%= _('Name') %></th><th></th></tr> | ||
| 4 | + <% @users_found.each do |user| %> | ||
| 5 | + <tr id="tr-<%= user.identifier %>"<%= profile.members.include?(user) ? 'style="display:none"' : '' %>> | ||
| 6 | + <td> | ||
| 7 | + <div id="<%= user.identifier %>" class="draggable-user"> | ||
| 8 | + <%= image_tag('/images/grip-clue.png') %> | ||
| 9 | + <%= profile_image(user, :icon) %> | ||
| 10 | + <%= [link_to_profile(user.short_name + " (#{user.identifier})", user.identifier, :title => user.name), | ||
| 11 | + (user.sex ? gettext(user.sex.capitalize) : _('Sex not informed')), | ||
| 12 | + user.location.empty? ? nil : user.location ].compact.join(' — ') %> | ||
| 13 | + </div> | ||
| 14 | + <%= draggable_element(user.identifier, :revert => true) %> | ||
| 15 | + </td> | ||
| 16 | + <td> | ||
| 17 | + <%= button_to_remote_without_text(:add, _('Add member'), | ||
| 18 | + { :loading => '$("members-list").addClassName("loading")', | ||
| 19 | + :update => 'members-list', | ||
| 20 | + :url => {:action => 'add_member', :profile => profile.identifier, :id => user.identifier}, | ||
| 21 | + :success => "$('tr-#{user.identifier}').hide()", | ||
| 22 | + :complete => '$("members-list").removeClassName("loading")'}) %> | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + </td> | ||
| 26 | + </tr> | ||
| 27 | + <% end if @users_found %> | ||
| 28 | +</table> |
app/views/profile_members/index.rhtml
| 1 | -<h2> <%= _('Listing Members') %> </h2> | ||
| 2 | - | ||
| 3 | -<%= link_to _('Affiliate yourself'), :action => 'add_role', :person => current_user.person, :role => @member_role if @member_role %> | ||
| 4 | - | ||
| 5 | -<table> | ||
| 6 | - <tr> | ||
| 7 | - <th><%= _('Member') %></th> | ||
| 8 | - <th><%= _('Actions') %></th> | ||
| 9 | - </tr> | ||
| 10 | - <% @members.each do |m| %> | ||
| 11 | - <tr> | ||
| 12 | - <td><%= m.name %> </td> | ||
| 13 | - <td> | ||
| 14 | - <%= button_without_text :edit, _('Edit'), :action => 'change_role', :id => m %> | ||
| 15 | - <%= button_without_text :delete, _('Remove'), :action => 'unassociate', :id => m %> | ||
| 16 | - </td> | ||
| 17 | - </tr> | ||
| 18 | - <% end %> | ||
| 19 | -</table> | 1 | +<div id="members-list"> |
| 2 | + <%= render :partial => 'members_list' %> | ||
| 3 | +</div> | ||
| 20 | 4 | ||
| 21 | <% button_bar do %> | 5 | <% button_bar do %> |
| 22 | <%= button :back, _('Back'), :controller => 'profile_editor' %> | 6 | <%= button :back, _('Back'), :controller => 'profile_editor' %> |
| 7 | + <%= button :add, _('Add members'), :action => 'add_members' if profile.enterprise? %> | ||
| 23 | <% end %> | 8 | <% end %> |
public/designs/icons/tango/style.css
| @@ -17,6 +17,7 @@ | @@ -17,6 +17,7 @@ | ||
| 17 | .icon-back { background-image: url(Tango/16x16/actions/back.png) } | 17 | .icon-back { background-image: url(Tango/16x16/actions/back.png) } |
| 18 | .icon-next { background-image: url(Tango/16x16/actions/go-next.png) } | 18 | .icon-next { background-image: url(Tango/16x16/actions/go-next.png) } |
| 19 | .icon-add { background-image: url(Tango/16x16/actions/add.png) } | 19 | .icon-add { background-image: url(Tango/16x16/actions/add.png) } |
| 20 | +.icon-remove { background-image: url(Tango/16x16/actions/gtk-remove.png) } | ||
| 20 | .icon-more { background-image: url(Tango/16x16/actions/add.png) } | 21 | .icon-more { background-image: url(Tango/16x16/actions/add.png) } |
| 21 | .icon-up { background-image: url(Tango/16x16/actions/go-up.png) } | 22 | .icon-up { background-image: url(Tango/16x16/actions/go-up.png) } |
| 22 | .icon-down { background-image: url(Tango/16x16/actions/go-down.png) } | 23 | .icon-down { background-image: url(Tango/16x16/actions/go-down.png) } |
159 Bytes
| @@ -0,0 +1,54 @@ | @@ -0,0 +1,54 @@ | ||
| 1 | +.no-boxes { | ||
| 2 | + margin: 30px | ||
| 3 | +} | ||
| 4 | + | ||
| 5 | +#users-list { | ||
| 6 | + float: left; | ||
| 7 | + width: 60%; | ||
| 8 | +} | ||
| 9 | + | ||
| 10 | +.msie6 #users-list { | ||
| 11 | + position: relative; | ||
| 12 | +} | ||
| 13 | + | ||
| 14 | +#users-list a.icon-add{ | ||
| 15 | + float: right; | ||
| 16 | +} | ||
| 17 | + | ||
| 18 | +.msie #users-list a.icon-add{ | ||
| 19 | + display: block; | ||
| 20 | +} | ||
| 21 | + | ||
| 22 | +.draggable-user { | ||
| 23 | + xwidth: 170px; | ||
| 24 | + cursor: move; | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +#members-list.add-members { | ||
| 28 | + float: right; | ||
| 29 | + width: 30%; | ||
| 30 | + text-align: center; | ||
| 31 | +} | ||
| 32 | + | ||
| 33 | +.members-buttons-cell { | ||
| 34 | + width: 60px; | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +.msie .members-buttons-cell a { | ||
| 38 | + position: relative; | ||
| 39 | + display: block; | ||
| 40 | + float: left; | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +.msie6 .button-bar a { | ||
| 44 | + position: relative; | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +.loading { | ||
| 48 | + cursor: progress; | ||
| 49 | + background: transparent url(../images/loading.gif) no-repeat scroll center 50px; | ||
| 50 | +} | ||
| 51 | + | ||
| 52 | +table { | ||
| 53 | + text-align: left; | ||
| 54 | +} |
test/functional/profile_members_controller_test.rb
| @@ -90,8 +90,8 @@ class ProfileMembersControllerTest < Test::Unit::TestCase | @@ -90,8 +90,8 @@ class ProfileMembersControllerTest < Test::Unit::TestCase | ||
| 90 | login_as :admin_user | 90 | login_as :admin_user |
| 91 | get :unassociate, :profile => com.identifier, :id => member | 91 | get :unassociate, :profile => com.identifier, :id => member |
| 92 | 92 | ||
| 93 | - assert_response :redirect | ||
| 94 | - assert_redirected_to :action => 'index' | 93 | + assert_response :success |
| 94 | + assert_equal nil, @response.layout | ||
| 95 | member.reload | 95 | member.reload |
| 96 | com.reload | 96 | com.reload |
| 97 | assert_not_includes com.members, member | 97 | assert_not_includes com.members, member |
| @@ -112,4 +112,100 @@ class ProfileMembersControllerTest < Test::Unit::TestCase | @@ -112,4 +112,100 @@ class ProfileMembersControllerTest < Test::Unit::TestCase | ||
| 112 | assert_not_includes assigns(:roles), role | 112 | assert_not_includes assigns(:roles), role |
| 113 | end | 113 | end |
| 114 | 114 | ||
| 115 | + should 'enterprises have a add members button' do | ||
| 116 | + ent = Enterprise.create!(:name => 'Test Ent', :identifier => 'test_ent') | ||
| 117 | + u = create_user_with_permission('test_user', 'manage_memberships', ent) | ||
| 118 | + login_as :test_user | ||
| 119 | + | ||
| 120 | + get :index, :profile => ent.identifier | ||
| 121 | + assert_tag :tag => 'a', :attributes => {:href => /add_members/} | ||
| 122 | + end | ||
| 123 | + | ||
| 124 | + should 'not display add members button for communities' do | ||
| 125 | + com = Community.create!(:name => 'Test Com', :identifier => 'test_com') | ||
| 126 | + u = create_user_with_permission('test_user', 'manage_memberships', com) | ||
| 127 | + login_as :test_user | ||
| 128 | + | ||
| 129 | + get :index, :profile => com.identifier | ||
| 130 | + assert_no_tag :tag => 'a', :attributes => {:href => /add_members/} | ||
| 131 | + end | ||
| 132 | + | ||
| 133 | + should 'have a add_members page' do | ||
| 134 | + ent = Enterprise.create!(:name => 'Test Ent', :identifier => 'test_ent') | ||
| 135 | + u = create_user_with_permission('test_user', 'manage_memberships', ent) | ||
| 136 | + login_as :test_user | ||
| 137 | + | ||
| 138 | + assert_nothing_raised do | ||
| 139 | + get :add_members, :profile => ent.identifier | ||
| 140 | + end | ||
| 141 | + | ||
| 142 | + end | ||
| 143 | + | ||
| 144 | + should 'list current members when adding new members' do | ||
| 145 | + ent = Enterprise.create!(:name => 'Test Ent', :identifier => 'test_ent') | ||
| 146 | + p = create_user_with_permission('test_user', 'manage_memberships', ent) | ||
| 147 | + login_as :test_user | ||
| 148 | + | ||
| 149 | + get :add_members, :profile => ent.identifier | ||
| 150 | + ent.reload | ||
| 151 | + assert_includes ent.members, p | ||
| 152 | + end | ||
| 153 | + | ||
| 154 | + should 'add member to profile' do | ||
| 155 | + ent = Enterprise.create!(:name => 'Test Ent', :identifier => 'test_ent') | ||
| 156 | + p = create_user_with_permission('test_user', 'manage_memberships', ent) | ||
| 157 | + login_as :test_user | ||
| 158 | + | ||
| 159 | + u = create_user('member_wannabe').person | ||
| 160 | + post :add_member, :profile => ent.identifier, :id => u.identifier | ||
| 161 | + ent.reload | ||
| 162 | + | ||
| 163 | + assert_includes ent.members, p | ||
| 164 | + assert_includes ent.members, u | ||
| 165 | + end | ||
| 166 | + | ||
| 167 | + should 'add member with all roles' do | ||
| 168 | + ent = Enterprise.create!(:name => 'Test Ent', :identifier => 'test_ent') | ||
| 169 | + p = create_user_with_permission('test_user', 'manage_memberships', ent) | ||
| 170 | + login_as :test_user | ||
| 171 | + | ||
| 172 | + u = create_user('member_wannabe').person | ||
| 173 | + post :add_member, :profile => ent.identifier, :id => u.identifier | ||
| 174 | + | ||
| 175 | + assert_equivalent Profile::Roles.all_roles(ent.environment).compact, u.role_assignments.find_all_by_resource_id(ent.id).map(&:role).compact | ||
| 176 | + end | ||
| 177 | + | ||
| 178 | + should 'not add member to community' do | ||
| 179 | + com = Community.create!(:name => 'Test Com', :identifier => 'test_com') | ||
| 180 | + p = create_user_with_permission('test_user', 'manage_memberships', com) | ||
| 181 | + login_as :test_user | ||
| 182 | + | ||
| 183 | + u = create_user('member_wannabe').person | ||
| 184 | + post :add_member, :profile => com.identifier, :id => u.identifier | ||
| 185 | + com.reload | ||
| 186 | + | ||
| 187 | + assert_not_includes com.members, u | ||
| 188 | + end | ||
| 189 | + | ||
| 190 | + should 'find users' do | ||
| 191 | + ent = Enterprise.create!(:name => 'Test Ent', :identifier => 'test_ent') | ||
| 192 | + user = create_user('test_user').person | ||
| 193 | + u = create_user_with_permission('ent_user', 'manage_memberships', ent) | ||
| 194 | + login_as :ent_user | ||
| 195 | + | ||
| 196 | + get :find_users, :profile => ent.identifier, :query => 'test*' | ||
| 197 | + | ||
| 198 | + assert_includes assigns(:users_found), user | ||
| 199 | + end | ||
| 200 | + | ||
| 201 | + should 'not appear add button for member in add members page' do | ||
| 202 | + ent = Enterprise.create!(:name => 'Test Ent', :identifier => 'test_ent') | ||
| 203 | + p = create_user_with_permission('test_user', 'manage_memberships', ent) | ||
| 204 | + login_as :test_user | ||
| 205 | + | ||
| 206 | + get :find_users, :profile => ent.identifier, :query => 'test*' | ||
| 207 | + | ||
| 208 | + assert_tag :tag => 'tr', :attributes => {:id => 'tr-test_user', :style => 'display:none'} | ||
| 209 | + end | ||
| 210 | + | ||
| 115 | end | 211 | end |