Commit 9dfe5a7c15111e4788674c1def837fca5a271831

Authored by Leandro Nunes dos Santos
2 parents cdf9ac9b f4ebf2ab

Merge branches 'ActionItem2882' and 'ActionItem2882_merge' into ActionItem2882_merge

app/controllers/admin/users_controller.rb
... ... @@ -4,12 +4,62 @@ class UsersController < AdminController
4 4  
5 5 protect 'manage_environment_users', :environment
6 6  
  7 + include UsersHelper
  8 +
  9 + def per_page
  10 + 10
  11 + end
  12 +
7 13 def index
  14 + @filter = params[:filter]
  15 + if @filter.blank? || @filter == 'all_users'
  16 + @filter = 'all_users'
  17 + scope = environment.people.no_templates(environment)
  18 + elsif @filter == 'admin_users'
  19 + scope = environment.people.no_templates(environment).admins
  20 + elsif @filter == 'activated_users'
  21 + scope = environment.people.no_templates(environment).activated
  22 + elsif @filter == 'deactivated_users'
  23 + scope = environment.people.no_templates(environment).deactivated
  24 + end
  25 + @q = params[:q]
  26 + if @q.blank?
  27 + @collection = scope.paginate(:per_page => per_page, :page => params[:npage])
  28 + else
  29 + @collection = find_by_contents(:people, scope, @q, {:per_page => per_page, :page => params[:npage]})[:results]
  30 + end
  31 + end
  32 +
  33 + def set_admin_role
  34 + person = environment.people.find(params[:id])
  35 + environment.add_admin(person)
  36 + redirect_to :action => :index, :q => params[:q], :filter => params[:filter]
  37 + end
  38 +
  39 + def reset_admin_role
  40 + person = environment.people.find(params[:id])
  41 + environment.remove_admin(person)
  42 + redirect_to :action => :index, :q => params[:q], :filter => params[:filter]
  43 + end
  44 +
  45 + def activate
  46 + person = environment.people.find(params[:id])
  47 + person.user.activate
  48 + redirect_to :action => :index, :q => params[:q], :filter => params[:filter]
  49 + end
  50 +
  51 + def deactivate
  52 + person = environment.people.find(params[:id])
  53 + person.user.deactivate
  54 + redirect_to :action => :index, :q => params[:q], :filter => params[:filter]
  55 + end
  56 +
  57 + def download
8 58 respond_to do |format|
9 59 format.html
10 60 format.xml do
11   - @users = User.find(:all, :conditions => {:environment_id => environment.id}, :include => [:person])
12   - send_data @users.to_xml(
  61 + users = User.find(:all, :conditions => {:environment_id => environment.id}, :include => [:person])
  62 + send_data users.to_xml(
13 63 :skip_types => true,
14 64 :only => %w[email login created_at updated_at],
15 65 :include => { :person => {:only => %w[name updated_at created_at address birth_date contact_phone identifier lat lng] } }),
... ...
app/controllers/application_controller.rb
... ... @@ -79,7 +79,7 @@ class ApplicationController < ActionController::Base
79 79  
80 80 helper_method :current_person, :current_person
81 81  
82   - protected
  82 + # protected
83 83  
84 84 def setup_multitenancy
85 85 Noosfero::MultiTenancy.setup!(request.host)
... ...
app/helpers/users_helper.rb 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +module UsersHelper
  2 +
  3 + FILTER_TRANSLATION = {
  4 + 'all_users' => _('All users'),
  5 + 'admin_users' => _('Admin users'),
  6 + 'activated_users' => _('Activated users'),
  7 + 'deactivated_users' => _('Deativated users'),
  8 + }
  9 +
  10 + def filter_selector(filter, float = 'right')
  11 + options = options_for_select(FILTER_TRANSLATION.map {|key, name| [name, key]}, :selected => filter)
  12 + url_params = url_for(params.merge(:filter => 'FILTER'))
  13 + onchange = "document.location.href = '#{url_params}'.replace('FILTER', this.value)"
  14 + select_field = select_tag(:filter, options, :onchange => onchange)
  15 + content_tag('div',
  16 + content_tag('strong', _('Filter')) + ': ' + select_field,
  17 + :class => "environment-users-customize-search"
  18 + )
  19 + end
  20 +
  21 + def filter_title(filter)
  22 + FILTER_TRANSLATION[filter]
  23 + end
  24 +
  25 +end
... ...
app/models/person.rb
... ... @@ -75,6 +75,10 @@ class Person < Profile
75 75 named_scope :abusers, :joins => :abuse_complaints, :conditions => ['tasks.status = 3'], :select => 'DISTINCT profiles.*'
76 76 named_scope :non_abusers, :joins => "LEFT JOIN tasks ON profiles.id = tasks.requestor_id AND tasks.type='AbuseComplaint'", :conditions => ["tasks.status != 3 OR tasks.id is NULL"], :select => "DISTINCT profiles.*"
77 77  
  78 + named_scope :admins, :joins => [:role_assignments => :role], :conditions => ['roles.key = ?', 'environment_administrator' ]
  79 + named_scope :activated, :joins => :user, :conditions => ['users.activation_code IS NULL AND users.activated_at IS NOT NULL']
  80 + named_scope :deactivated, :joins => :user, :conditions => ['NOT (users.activation_code IS NULL AND users.activated_at IS NOT NULL)']
  81 +
78 82 after_destroy do |person|
79 83 Friendship.find(:all, :conditions => { :friend_id => person.id}).each { |friendship| friendship.destroy }
80 84 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 &lt; 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/users/_index_buttons.rhtml 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +<% button_bar do %>
  2 + <%= button :'text-plain', _('User list as [CSV]'), :action => :download, :format => 'csv' %>
  3 + <%= button :'text-html', _('User list as [XML]'), :action => :download, :format => 'xml' %>
  4 + <%= button :send, _('Send e-mail to all users'), :action => 'send_mail' %>
  5 + <%= button :back, _('Back'), :controller => 'admin_panel' %>
  6 +<% end %>
... ...
app/views/users/_users_list.rhtml 0 → 100644
... ... @@ -0,0 +1,33 @@
  1 +<div class="environment-users-results-header">
  2 + <div id='environment-users-filter-title'><%= filter_title(@filter) %></div>
  3 + <%= filter_selector(@filter) %>
  4 + <div style="clear: both"></div>
  5 +</div>
  6 +
  7 +<table>
  8 + <tr>
  9 + <th><%= _('Member') %></th>
  10 + <th><%= _('Actions') %></th>
  11 + </tr>
  12 + <% @collection.each do |p| %>
  13 + <tr title="<%= p.name %>">
  14 + <td><%= link_to_profile p.short_name, p.identifier, :title => p.name %> </td>
  15 + <td>
  16 + <div class="members-buttons-cell">
  17 + <% if p.is_admin? %>
  18 + <%= button_without_text :'reset-admin-role', _('Reset admin role'), :action => 'reset_admin_role', :id => p, :q => @q, :filter => @filter %>
  19 + <% else %>
  20 + <%= button_without_text :'set-admin-role', _('Set admin role'), :action => 'set_admin_role', :id => p, :q => @q, :filter => @filter %>
  21 + <% end %>
  22 + <% if !p.user.activated? %>
  23 + <%= button_without_text :'activate-user', _('Activate user'), :action => 'activate', :id => p, :q => @q, :filter => @filter %>
  24 + <% else %>
  25 + <%= button_without_text :'deactivate-user', _('Deactivate user'), :action => 'deactivate', :id => p, :q => @q, :filter => @filter %>
  26 + <% end %>
  27 + </div>
  28 + </td>
  29 + </tr>
  30 + <% end %>
  31 +</table>
  32 +
  33 +<%= pagination_links @collection, {:param_name => 'npage', :page_links => true} %>
... ...
app/views/users/_users_search_form.rhtml 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 + <div class="search-field">
  2 + <span class="formfield">
  3 + <%= text_field_tag 'q', @q, :title => _("Find users") %>
  4 + </span>
  5 + <%= submit_button(:search, _('Search')) %>
  6 + </div>
0 7 \ No newline at end of file
... ...
app/views/users/index.rhtml
1 1 <h1><%= _('Manage users') %></h1>
2 2  
3   -<ul>
4   - <li>
5   - <%= _('Download users list') %>:
6   - <%= link_to '[CSV]', :format => 'csv' %>
7   - <%= link_to '[XML]', :format => 'xml' %>
8   - </li>
9   - <li>
10   - <%= link_to _('Send e-mail to users'), :action => 'send_mail' %>
11   - </li>
12   -</ul>
13   -
14   -<% button_bar do %>
15   - <%= button :back, _('Back to admin panel'), :controller => 'admin_panel' %>
  3 +<% form_tag( { :action => 'index' }, :method => 'get', :class => 'users-search' ) do %>
  4 +<div id="search-users">
  5 + <%= render :partial => 'users_search_form' %>
  6 +</div>
  7 +<div id="users-list">
  8 + <%= render :partial => 'users_list' %>
  9 +</div>
16 10 <% end %>
  11 +
  12 +<%= render :partial => 'index_buttons' %>
17 13 \ No newline at end of file
... ...
public/designs/icons/tango/style.css
... ... @@ -99,6 +99,11 @@
99 99 .icon-user-unknown { background-image: url(Tango/16x16/status/dialog-error.png) }
100 100 .icon-alert { background-image: url(Tango/16x16/status/dialog-warning.png) }
101 101  
  102 +.icon-activate-user { background-image: url(Tango/16x16/emblems/emblem-system.png) }
  103 +.icon-deactivate-user { background-image: url(Tango/16x16/emblems/emblem-unreadable.png) }
  104 +.icon-set-admin-role { background-image: url(mod/16x16/apps/user.png) }
  105 +.icon-reset-admin-role { background-image: url(/images/icons-app/person-icon.png) }
  106 +
102 107 /******************LARGE ICONS********************/
103 108 .image-gallery-item .folder { background-image: url(mod/96x96/places/folder.png) }
104 109 .image-gallery-item .gallery { background-image: url(mod/96x96/mimetypes/image-x-generic.png) }
... ...
public/stylesheets/application.css
... ... @@ -4161,6 +4161,33 @@ h1#agenda-title {
4161 4161 -webkit-border-radius:10px;
4162 4162 }
4163 4163  
  4164 +/* ==> public/stylesheets/controller_environment_users.css <== */
  4165 +.controller-environment_users table {
  4166 + text-align: left;
  4167 +}
  4168 +
  4169 +#environment-users-search form {
  4170 + padding: 10px;
  4171 + margin-bottom: 15px;
  4172 + background-color: #E6E6E6;
  4173 + -moz-border-radius: 5px;
  4174 + -webkit-border-radius: 5px;
  4175 +}
  4176 +
  4177 +.environment-users-results-header {
  4178 + font-size: 0.9em;
  4179 + padding: 6px 0px 0px 0px;
  4180 + margin:0 0 5px 0;
  4181 + border-bottom: 2px dotted #999;
  4182 + text-align: right;
  4183 +}
  4184 +#environment-users-filter-title {
  4185 + font-weight: bold;
  4186 + font-size: 130%;
  4187 + line-height: 35px;
  4188 + float: left;
  4189 +}
  4190 +
4164 4191 /* * * Profile search * * * * * * * */
4165 4192  
4166 4193 #public-profile-search, #profile-search-results form, .profile-search-block form {
... ...
test/functional/users_controller_test.rb
... ... @@ -6,11 +6,16 @@ class UsersController; def rescue_action(e) raise e end; end
6 6  
7 7 class UsersControllerTest < ActionController::TestCase
8 8  
9   - all_fixtures
10 9 def setup
11 10 @controller = UsersController.new
12 11 @request = ActionController::TestRequest.new
13 12 @response = ActionController::TestResponse.new
  13 +
  14 +
  15 + Environment.delete_all
  16 + Environment.create(:name => 'some env', :is_default => true)
  17 + admin_user = create_user_with_permission('adminuser', 'manage_environment_users', Environment.default)
  18 + login_as('adminuser')
14 19 end
15 20  
16 21 should 'not access without right permission' do
... ... @@ -28,11 +33,83 @@ class UsersControllerTest &lt; ActionController::TestCase
28 33 assert_response :success
29 34 end
30 35  
  36 + should 'blank search results include activated and deactivated users' do
  37 + deactivated = create_user('deactivated')
  38 + deactivated.activated_at = nil
  39 + deactivated.person.visible = false
  40 + deactivated.save!
  41 + get :index, :q => ''
  42 + assert_tag :tag => 'div', :attributes => { :id => /users-list/ }, :descendant => {:tag => 'a', :attributes => {:title => /adminuser/}}
  43 + assert_tag :tag => 'div', :attributes => { :id => /users-list/ }, :descendant => {:tag => 'a', :attributes => {:title => /deactivated/}}
  44 + end
  45 +
  46 + should 'blank search include all users' do
  47 + (1..5).each {|i|
  48 + u = create_user('user'+i.to_s)
  49 + }
  50 + get :index, :q => '' # blank search
  51 + assert_tag :tag => 'div', :attributes => { :id => /users-list/ }, :descendant => {:tag => 'a', :attributes => {:title => /adminuser/}}
  52 + (1..5).each {|i|
  53 + u = 'user'+i.to_s
  54 + assert_tag :tag => 'div', :attributes => { :id => /users-list/ }, :descendant => {:tag => 'a', :attributes => {:title => u}}
  55 + }
  56 + end
  57 +
  58 + should 'search not include all users' do
  59 + (1..5).each {|i|
  60 + u = create_user('user'+i.to_s)
  61 + }
  62 + get :index, :q => 'er5' # search
  63 + assert_tag :tag => 'div', :attributes => { :id => /users-list/ }, :descendant => {:tag => 'a', :attributes => {:title => /user5/}}
  64 + (1..4).each {|i|
  65 + u = 'user'+i.to_s
  66 + assert_no_tag :tag => 'div', :attributes => { :id => /users-list/ }, :descendant => {:tag => 'a', :attributes => {:title => u}}
  67 + }
  68 + end
  69 +
  70 + should 'set admin role' do
  71 + u = create_user()
  72 + assert_equal false, u.person.is_admin?
  73 + post :set_admin_role, :id => u.person.id, :q => ''
  74 + u.reload
  75 + assert u.person.is_admin?
  76 + end
  77 +
  78 + should 'reset admin role' do
  79 + u = create_user()
  80 + e = Environment.default
  81 + e.add_admin(u.person)
  82 + u.reload
  83 + assert u.person.is_admin?
  84 + post :reset_admin_role, :id => u.person.id, :q => ''
  85 + u.reload
  86 + assert_equal false, u.person.is_admin?
  87 + end
  88 +
  89 + should 'activate user' do
  90 + u = create_user()
  91 + assert_equal false, u.activated?
  92 + post :activate, :id => u.person.id, :q => ''
  93 + u.reload
  94 + assert u.activated?
  95 + end
  96 +
  97 + should 'deactivate user' do
  98 + u = create_user()
  99 + u.activated_at = Time.now.utc
  100 + u.activation_code = nil
  101 + u.person.visible = true
  102 + assert u.activated?
  103 + post :deactivate, :id => u.person.id, :q => ''
  104 + u.reload
  105 + assert_equal false, u.activated?
  106 + end
  107 +
31 108 should 'response as XML to export users' do
32 109 admin_user = create_user_with_permission('admin_user', 'manage_environment_users', Environment.default)
33 110 login_as('admin_user')
34 111  
35   - get :index, :format => 'xml'
  112 + get :download, :format => 'xml'
36 113 assert_equal 'text/xml', @response.content_type
37 114 end
38 115  
... ... @@ -40,7 +117,7 @@ class UsersControllerTest &lt; ActionController::TestCase
40 117 admin_user = create_user_with_permission('admin_user', 'manage_environment_users', Environment.default)
41 118 login_as('admin_user')
42 119  
43   - get :index, :format => 'csv'
  120 + get :download, :format => 'csv'
44 121 assert_equal 'text/csv', @response.content_type
45 122 assert_equal 'name;email', @response.body.split("\n")[0]
46 123 end
... ...
test/unit/person_test.rb
... ... @@ -1335,4 +1335,56 @@ class PersonTest &lt; ActiveSupport::TestCase
1335 1335 assert_includes non_abusers, not_abuser
1336 1336 end
1337 1337  
  1338 + should 'admins named_scope return persons who are admin users' do
  1339 + Person.delete_all
  1340 + e = Environment.default
  1341 + admins = []
  1342 + (1..5).each {|i|
  1343 + u = create_user('user'+i.to_s)
  1344 + e.add_admin(u.person)
  1345 + admins << u.person
  1346 + }
  1347 + (6..10).each {|i|
  1348 + u = create_user('user'+i.to_s)
  1349 + }
  1350 + assert_equal admins, Person.admins
  1351 + end
  1352 +
  1353 + should 'activated named_scope return persons who are activated users' do
  1354 + Person.delete_all
  1355 + e = Environment.default
  1356 + activated = []
  1357 + (1..5).each {|i|
  1358 + u = create_user('user'+i.to_s)
  1359 + u.activated_at = Time.now.utc
  1360 + u.activation_code = nil
  1361 + u.save!
  1362 + activated << u.person
  1363 + }
  1364 + (6..10).each {|i|
  1365 + u = create_user('user'+i.to_s)
  1366 + u.activated_at = nil
  1367 + u.save!
  1368 + }
  1369 + assert_equal activated, Person.activated
  1370 + end
  1371 +
  1372 + should 'deactivated named_scope return persons who are deactivated users' do
  1373 + Person.delete_all
  1374 + e = Environment.default
  1375 + deactivated = []
  1376 + (1..5).each {|i|
  1377 + u = create_user('user'+i.to_s)
  1378 + u.activated_at = nil
  1379 + u.save!
  1380 + deactivated << u.person
  1381 + }
  1382 + (6..10).each {|i|
  1383 + u = create_user('user'+i.to_s)
  1384 + u.activated_at = Time.now.utc
  1385 + u.activation_code = nil
  1386 + u.save!
  1387 + }
  1388 + assert_equal deactivated, Person.deactivated
  1389 + end
1338 1390 end
... ...
test/unit/profile_test.rb
... ... @@ -1379,6 +1379,18 @@ class ProfileTest &lt; 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 &lt; 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')
... ...