Commit d09c5df540181267cc6d2a71a7bf8465f43b33f5
1 parent
ce0d03ab
Exists in
master
and in
29 other branches
Allow admins to set and reset admin role on environment users.
Allow admins to activate and deactivate environment users.
Showing
13 changed files
with
269 additions
and
0 deletions
Show diff stats
... | ... | @@ -0,0 +1,44 @@ |
1 | +class EnvironmentUsersController < AdminController | |
2 | + | |
3 | + protect 'manage_environment_users', :environment | |
4 | + | |
5 | + def per_page | |
6 | + 10 | |
7 | + end | |
8 | + | |
9 | + def index | |
10 | + @q = params[:q] | |
11 | + if @q.blank? | |
12 | + @collection = environment.people.no_templates(environment).paginate( | |
13 | + :per_page => per_page, | |
14 | + :page => params[:npage] | |
15 | + ) | |
16 | + else | |
17 | + @collection = find_by_contents(:people, environment.people.no_templates(environment), @q, {:per_page => per_page, :page => params[:npage]})[:results] | |
18 | + end | |
19 | + end | |
20 | + | |
21 | + def set_admin_role | |
22 | + @person = environment.people.find(params[:id]) | |
23 | + environment.add_admin(@person) | |
24 | + redirect_to :action => :index, :q => params[:q] | |
25 | + end | |
26 | + | |
27 | + def reset_admin_role | |
28 | + @person = environment.people.find(params[:id]) | |
29 | + environment.remove_admin(@person) | |
30 | + redirect_to :action => :index, :q => params[:q] | |
31 | + end | |
32 | + | |
33 | + def activate | |
34 | + @person = environment.people.find(params[:id]) | |
35 | + @person.user.activate | |
36 | + redirect_to :action => :index, :q => params[:q] | |
37 | + end | |
38 | + | |
39 | + def deactivate | |
40 | + @person = environment.people.find(params[:id]) | |
41 | + @person.user.deactivate | |
42 | + redirect_to :action => :index, :q => params[:q] | |
43 | + end | |
44 | +end | ... | ... |
app/models/profile.rb
... | ... | @@ -79,6 +79,7 @@ class Profile < ActiveRecord::Base |
79 | 79 | named_scope :enterprises, lambda { {:conditions => (Enterprise.send(:subclasses).map(&:name) << 'Enterprise').map { |klass| "profiles.type = '#{klass}'"}.join(" OR ")} } |
80 | 80 | named_scope :communities, lambda { {:conditions => (Community.send(:subclasses).map(&:name) << 'Community').map { |klass| "profiles.type = '#{klass}'"}.join(" OR ")} } |
81 | 81 | named_scope :templates, lambda { |environment| { :conditions => {:is_template => true, :environment_id => environment.id} } } |
82 | + named_scope :no_templates, lambda { |environment| { :conditions => {:is_template => false, :environment_id => environment.id} } } | |
82 | 83 | |
83 | 84 | def members |
84 | 85 | scopes = plugins.dispatch_scopes(:organization_members, self) | ... | ... |
app/models/user.rb
... | ... | @@ -143,6 +143,21 @@ class User < ActiveRecord::Base |
143 | 143 | end |
144 | 144 | end |
145 | 145 | |
146 | + # Deactivates the user in the database. | |
147 | + def deactivate | |
148 | + return false unless self.person | |
149 | + self.activated_at = nil | |
150 | + self.person.visible = false | |
151 | + begin | |
152 | + self.person.save! && self.save! | |
153 | + rescue Exception => exception | |
154 | + logger.error(exception.to_s) | |
155 | + false | |
156 | + else | |
157 | + true | |
158 | + end | |
159 | + end | |
160 | + | |
146 | 161 | def activated? |
147 | 162 | self.activation_code.nil? && !self.activated_at.nil? |
148 | 163 | end | ... | ... |
app/views/environment_users/_environment_users_search_form.rhtml
0 → 100644
... | ... | @@ -0,0 +1,8 @@ |
1 | +<% form_tag( { :controller => 'environment_users', :action => 'index' }, :method => 'get', :class => 'environment-users-search' ) do %> | |
2 | + <div class="search-field"> | |
3 | + <span class="formfield"> | |
4 | + <%= text_field_tag 'q', @q, :title => _("Find users") %> | |
5 | + </span> | |
6 | + <%= submit_button(:search, _('Search')) %> | |
7 | + </div> | |
8 | +<% end %> | ... | ... |
... | ... | @@ -0,0 +1,30 @@ |
1 | +<% title = _('All Users') %> | |
2 | + | |
3 | +<h3><%= title %></h3> | |
4 | +<table> | |
5 | + <tr> | |
6 | + <th><%= _('Member') %></th> | |
7 | + <th><%= _('Actions') %></th> | |
8 | + </tr> | |
9 | + <% @collection.each do |p| %> | |
10 | + <tr title="<%= p.name %>"> | |
11 | + <td><%= link_to_profile p.short_name, p.identifier, :title => p.name %> </td> | |
12 | + <td> | |
13 | + <div class="members-buttons-cell"> | |
14 | + <% if p.is_admin? %> | |
15 | + <%= button_without_text :'reset-admin-role', _('Reset admin role'), :action => 'reset_admin_role', :id => p, :q => @q %> | |
16 | + <% else %> | |
17 | + <%= button_without_text :'set-admin-role', _('Set admin role'), :action => 'set_admin_role', :id => p, :q => @q %> | |
18 | + <% end %> | |
19 | + <% if !p.user.activated? %> | |
20 | + <%= button_without_text :'activate-user', _('Activate user'), :action => 'activate', :id => p, :q => @q %> | |
21 | + <% else %> | |
22 | + <%= button_without_text :'deactivate-user', _('Deactivate user'), :action => 'deactivate', :id => p, :q => @q %> | |
23 | + <% end %> | |
24 | + </div> | |
25 | + </td> | |
26 | + </tr> | |
27 | + <% end %> | |
28 | +</table> | |
29 | + | |
30 | +<%= pagination_links @collection, {:param_name => 'npage', :page_links => true} %> | |
0 | 31 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,12 @@ |
1 | +<h1><%= _('Edit Users')%></h1> | |
2 | + | |
3 | +<%= render :partial => 'index_buttons' %> | |
4 | + | |
5 | +<div id="search-users"> | |
6 | + <%= render :partial => 'environment_users_search_form' %> | |
7 | +</div> | |
8 | +<div id="users-list"> | |
9 | + <%= render :partial => 'users_list' %> | |
10 | +</div> | |
11 | + | |
12 | +<%= render :partial => 'index_buttons' %> | ... | ... |
app/views/users/index.rhtml
public/designs/icons/tango/style.css
... | ... | @@ -101,6 +101,11 @@ |
101 | 101 | .icon-user-unknown { background-image: url(Tango/16x16/status/dialog-error.png) } |
102 | 102 | .icon-alert { background-image: url(Tango/16x16/status/dialog-warning.png) } |
103 | 103 | |
104 | +.icon-activate-user { background-image: url(Tango/16x16/emblems/emblem-system.png) } | |
105 | +.icon-deactivate-user { background-image: url(Tango/16x16/emblems/emblem-unreadable.png) } | |
106 | +.icon-set-admin-role { background-image: url(mod/16x16/apps/user.png) } | |
107 | +.icon-reset-admin-role { background-image: url(/images/icons-app/person-icon.png) } | |
108 | + | |
104 | 109 | /******************LARGE ICONS********************/ |
105 | 110 | .image-gallery-item .folder { background-image: url(mod/96x96/places/folder.png) } |
106 | 111 | .image-gallery-item .gallery { background-image: url(mod/96x96/mimetypes/image-x-generic.png) } | ... | ... |
public/stylesheets/application.css
... | ... | @@ -4137,6 +4137,20 @@ h1#agenda-title { |
4137 | 4137 | -webkit-border-radius:10px; |
4138 | 4138 | } |
4139 | 4139 | |
4140 | +/* ==> public/stylesheets/controller_environment_users.css <== */ | |
4141 | +.controller-environment_users table { | |
4142 | + text-align: left; | |
4143 | +} | |
4144 | + | |
4145 | +#environment-users-search form { | |
4146 | + padding: 10px; | |
4147 | + margin-bottom: 15px; | |
4148 | + background-color: #E6E6E6; | |
4149 | + -moz-border-radius: 5px; | |
4150 | + -webkit-border-radius: 5px; | |
4151 | +} | |
4152 | + | |
4153 | + | |
4140 | 4154 | /* * * Profile search * * * * * * * */ |
4141 | 4155 | |
4142 | 4156 | #public-profile-search, #profile-search-results form, .profile-search-block form { | ... | ... |
... | ... | @@ -0,0 +1,103 @@ |
1 | +require File.dirname(__FILE__) + '/../test_helper' | |
2 | +require 'environment_users_controller' | |
3 | + | |
4 | +# Re-raise errors caught by the controller. | |
5 | +class EnvironmentUsersController; def rescue_action(e) raise e end; end | |
6 | + | |
7 | +class EnvironmentUsersControllerTest < ActionController::TestCase | |
8 | + | |
9 | + # all_fixtures | |
10 | + def setup | |
11 | + @controller = EnvironmentUsersController.new | |
12 | + @request = ActionController::TestRequest.new | |
13 | + @response = ActionController::TestResponse.new | |
14 | + | |
15 | + admin_user = create_user_with_permission('adminuser', 'manage_environment_users', Environment.default) | |
16 | + login_as('adminuser') | |
17 | + end | |
18 | + | |
19 | + should 'not access without right permission' do | |
20 | + guest = create_user('guest') | |
21 | + login_as 'guest' | |
22 | + | |
23 | + get :index | |
24 | + assert_response 403 # forbidden | |
25 | + end | |
26 | + | |
27 | + should 'grant access with right permission' do | |
28 | + get :index | |
29 | + assert_response :success | |
30 | + end | |
31 | + | |
32 | + should 'blank search results include activated and deactivated users' do | |
33 | + deactivated = create_user('deactivated') | |
34 | + deactivated.activated_at = nil | |
35 | + deactivated.person.visible = false | |
36 | + deactivated.save! | |
37 | + get :index, :q => '' | |
38 | + assert_tag :tag => 'div', :attributes => { :id => /users-list/ }, :descendant => {:tag => 'a', :attributes => {:title => /adminuser/}} | |
39 | + assert_tag :tag => 'div', :attributes => { :id => /users-list/ }, :descendant => {:tag => 'a', :attributes => {:title => /deactivated/}} | |
40 | + end | |
41 | + | |
42 | + should 'blank search include all users' do | |
43 | + (1..5).each {|i| | |
44 | + u = create_user('user'+i.to_s) | |
45 | + } | |
46 | + get :index, :q => '' # blank search | |
47 | + assert_tag :tag => 'div', :attributes => { :id => /users-list/ }, :descendant => {:tag => 'a', :attributes => {:title => /adminuser/}} | |
48 | + (1..5).each {|i| | |
49 | + u = 'user'+i.to_s | |
50 | + assert_tag :tag => 'div', :attributes => { :id => /users-list/ }, :descendant => {:tag => 'a', :attributes => {:title => u}} | |
51 | + } | |
52 | + end | |
53 | + | |
54 | + should 'search not include all users' do | |
55 | + (1..5).each {|i| | |
56 | + u = create_user('user'+i.to_s) | |
57 | + } | |
58 | + get :index, :q => 'er5' # search | |
59 | + assert_tag :tag => 'div', :attributes => { :id => /users-list/ }, :descendant => {:tag => 'a', :attributes => {:title => /user5/}} | |
60 | + (1..4).each {|i| | |
61 | + u = 'user'+i.to_s | |
62 | + assert_no_tag :tag => 'div', :attributes => { :id => /users-list/ }, :descendant => {:tag => 'a', :attributes => {:title => u}} | |
63 | + } | |
64 | + end | |
65 | + | |
66 | + should 'set admin role' do | |
67 | + u = create_user() | |
68 | + assert_equal false, u.person.is_admin? | |
69 | + post :set_admin_role, :id => u.person.id, :q => '' | |
70 | + u.reload | |
71 | + assert u.person.is_admin? | |
72 | + end | |
73 | + | |
74 | + should 'reset admin role' do | |
75 | + u = create_user() | |
76 | + e = Environment.default | |
77 | + e.add_admin(u.person) | |
78 | + u.reload | |
79 | + assert u.person.is_admin? | |
80 | + post :reset_admin_role, :id => u.person.id, :q => '' | |
81 | + u.reload | |
82 | + assert_equal false, u.person.is_admin? | |
83 | + end | |
84 | + | |
85 | + should 'activate user' do | |
86 | + u = create_user() | |
87 | + assert_equal false, u.activated? | |
88 | + post :activate, :id => u.person.id, :q => '' | |
89 | + u.reload | |
90 | + assert u.activated? | |
91 | + end | |
92 | + | |
93 | + should 'deactivate user' do | |
94 | + u = create_user() | |
95 | + u.activated_at = Time.now.utc | |
96 | + u.activation_code = nil | |
97 | + u.person.visible = true | |
98 | + assert u.activated? | |
99 | + post :deactivate, :id => u.person.id, :q => '' | |
100 | + u.reload | |
101 | + assert_equal false, u.activated? | |
102 | + end | |
103 | +end | ... | ... |
test/unit/profile_test.rb
... | ... | @@ -1379,6 +1379,18 @@ class ProfileTest < ActiveSupport::TestCase |
1379 | 1379 | assert_not_includes Profile.templates(Environment.default), profile |
1380 | 1380 | end |
1381 | 1381 | |
1382 | + should 'return a list of profiles that are not templates' do | |
1383 | + p1 = fast_create(Profile, :is_template => false) | |
1384 | + p2 = fast_create(Profile, :is_template => false) | |
1385 | + t1 = fast_create(Profile, :is_template => true) | |
1386 | + t2 = fast_create(Profile, :is_template => true) | |
1387 | + | |
1388 | + assert_includes Profile.no_templates(Environment.default), p1 | |
1389 | + assert_includes Profile.no_templates(Environment.default), p2 | |
1390 | + assert_not_includes Profile.no_templates(Environment.default), t1 | |
1391 | + assert_not_includes Profile.no_templates(Environment.default), t2 | |
1392 | + end | |
1393 | + | |
1382 | 1394 | should 'not crash on a profile update with a destroyed template' do |
1383 | 1395 | template = fast_create(Profile, :is_template => true) |
1384 | 1396 | profile = fast_create(Profile, :template_id => template.id) | ... | ... |
test/unit/user_test.rb
... | ... | @@ -518,6 +518,25 @@ class UserTest < ActiveSupport::TestCase |
518 | 518 | end |
519 | 519 | end |
520 | 520 | |
521 | + should 'deactivate an user' do | |
522 | + user = new_user | |
523 | + user.activated_at = Time.now.utc | |
524 | + user.person.visible = true | |
525 | + assert user.deactivate | |
526 | + assert_nil user.activated_at | |
527 | + assert !user.person.visible | |
528 | + end | |
529 | + | |
530 | + should 'return if the user is deactivated' do | |
531 | + user = new_user | |
532 | + user.activated_at = Time.now.utc | |
533 | + user.activation_code = nil | |
534 | + user.person.visible = true | |
535 | + assert user.activated? | |
536 | + user.deactivate | |
537 | + assert !user.activated? | |
538 | + end | |
539 | + | |
521 | 540 | should 'activate right after creation when confirmation is not required' do |
522 | 541 | e = Environment.default |
523 | 542 | e.enable('skip_new_user_email_confirmation') | ... | ... |