Commit c9def945d4222eeb8026a0311495259bf99267a1

Authored by Dmitriy Zaporozhets
1 parent c0df0cd7

User blocking improved. Admin area styled

CHANGELOG
1 1 v 2.4.0
  2 + - Ability to block user
  3 + - Simplified dashboard area
  4 + - Improved admin area
2 5 - Accept merge request
  6 + - Bootstrap 2.0
  7 + - Responsive layout
  8 + - Big commits handling
  9 + - Perfomance improved
  10 + - Milestones
3 11  
4 12 v 2.3.1
5 13 - Issues pagination
... ...
app/assets/stylesheets/gitlab_bootstrap.scss
... ... @@ -450,3 +450,17 @@ form {
450 450 }
451 451  
452 452 }
  453 +
  454 +table.admin-table {
  455 + @extend .table-bordered;
  456 + @extend .zebra-striped;
  457 + th {
  458 + border-color: #CCC;
  459 + border-bottom: 1px solid #bbb;
  460 + background:#eee;
  461 + background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
  462 + background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
  463 + background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
  464 + background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
  465 + }
  466 +}
... ...
app/controllers/admin/users_controller.rb
... ... @@ -4,7 +4,9 @@ class Admin::UsersController < ApplicationController
4 4 before_filter :authenticate_admin!
5 5  
6 6 def index
7   - @admin_users = User.page(params[:page])
  7 + @admin_users = User.scoped
  8 + @admin_users = @admin_users.filter(params[:filter])
  9 + @admin_users = @admin_users.order("updated_at DESC").page(params[:page])
8 10 end
9 11  
10 12 def show
... ... @@ -38,13 +40,31 @@ class Admin::UsersController < ApplicationController
38 40 @admin_user = User.find(params[:id])
39 41 end
40 42  
  43 + def block
  44 + @admin_user = User.find(params[:id])
  45 +
  46 + if @admin_user.block
  47 + redirect_to :back, alert: "Successfully blocked"
  48 + else
  49 + redirect_to :back, alert: "Error occured. User was not blocked"
  50 + end
  51 + end
  52 +
  53 + def unblock
  54 + @admin_user = User.find(params[:id])
  55 +
  56 + if @admin_user.update_attribute(:blocked, false)
  57 + redirect_to :back, alert: "Successfully unblocked"
  58 + else
  59 + redirect_to :back, alert: "Error occured. User was not unblocked"
  60 + end
  61 + end
  62 +
41 63 def create
42 64 admin = params[:user].delete("admin")
43   - blocked = params[:user].delete("blocked")
44 65  
45 66 @admin_user = User.new(params[:user])
46 67 @admin_user.admin = (admin && admin.to_i > 0)
47   - @admin_user.blocked = blocked
48 68  
49 69 respond_to do |format|
50 70 if @admin_user.save
... ... @@ -59,7 +79,6 @@ class Admin::UsersController < ApplicationController
59 79  
60 80 def update
61 81 admin = params[:user].delete("admin")
62   - blocked = params[:user].delete("blocked")
63 82  
64 83 if params[:user][:password].blank?
65 84 params[:user].delete(:password)
... ... @@ -68,7 +87,6 @@ class Admin::UsersController < ApplicationController
68 87  
69 88 @admin_user = User.find(params[:id])
70 89 @admin_user.admin = (admin && admin.to_i > 0)
71   - @admin_user.blocked = blocked
72 90  
73 91 respond_to do |format|
74 92 if @admin_user.update_attributes(params[:user])
... ...
app/controllers/application_controller.rb
1 1 class ApplicationController < ActionController::Base
2 2 before_filter :authenticate_user!
  3 + before_filter :reject_blocked!
3 4 before_filter :set_current_user_for_mailer
4 5 protect_from_forgery
5 6 helper_method :abilities, :can?
... ... @@ -16,6 +17,14 @@ class ApplicationController &lt; ActionController::Base
16 17  
17 18 protected
18 19  
  20 + def reject_blocked!
  21 + if current_user && current_user.blocked
  22 + sign_out current_user
  23 + flash[:alert] = "Your account was blocked"
  24 + redirect_to new_user_session_path
  25 + end
  26 + end
  27 +
19 28 def after_sign_in_path_for resource
20 29 if resource.is_a?(User) && resource.respond_to?(:blocked) && resource.blocked
21 30 sign_out resource
... ...
app/models/user.rb
... ... @@ -48,7 +48,25 @@ class User &lt; ActiveRecord::Base
48 48  
49 49 before_create :ensure_authentication_token
50 50 alias_attribute :private_token, :authentication_token
  51 +
51 52 scope :not_in_project, lambda { |project| where("id not in (:ids)", :ids => project.users.map(&:id) ) }
  53 + scope :admins, where(:admin => true)
  54 + scope :blocked, where(:blocked => true)
  55 + scope :active, where(:blocked => false)
  56 +
  57 + def self.filter filter_name
  58 + case filter_name
  59 + when "admins"; self.admins
  60 + when "blocked"; self.blocked
  61 + when "wop"; self.without_projects
  62 + else
  63 + self.active
  64 + end
  65 + end
  66 +
  67 + def self.without_projects
  68 + where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)')
  69 + end
52 70  
53 71 def identifier
54 72 email.gsub /[@.]/, "_"
... ... @@ -58,6 +76,7 @@ class User &lt; ActiveRecord::Base
58 76 admin
59 77 end
60 78  
  79 +
61 80 def require_ssh_key?
62 81 keys.count == 0
63 82 end
... ... @@ -101,6 +120,17 @@ class User &lt; ActiveRecord::Base
101 120 def project_ids
102 121 projects.map(&:id)
103 122 end
  123 +
  124 + # Remove user from all projects and
  125 + # set blocked attribute to true
  126 + def block
  127 + users_projects.all.each do |membership|
  128 + return false unless membership.destroy
  129 + end
  130 +
  131 + self.blocked = true
  132 + save
  133 + end
104 134 end
105 135 # == Schema Information
106 136 #
... ...
app/views/admin/projects/index.html.haml
... ... @@ -2,7 +2,7 @@
2 2 Projects
3 3 = link_to 'New Project', new_admin_project_path, :class => "btn small right"
4 4 %br
5   -%table.zebra-striped.table-bordered
  5 +%table.admin-table
6 6 %thead
7 7 %th Name
8 8 %th Path
... ...
app/views/admin/projects/show.html.haml
... ... @@ -2,9 +2,8 @@
2 2 = @admin_project.name
3 3 = link_to 'Edit', edit_admin_project_path(@admin_project), :class => "btn right small"
4 4  
5   -%hr
6   -
7   -%table.zebra-striped
  5 +%br
  6 +%table.zebra-striped.table-bordered
8 7 %tr
9 8 %td
10 9 %b
... ... @@ -29,47 +28,47 @@
29 28 Description:
30 29 %td
31 30 = @admin_project.description
  31 +%br
  32 +%h3
  33 + Team
  34 + %small
  35 + (#{@admin_project.users_projects.count})
  36 +%br
  37 +%table.zebra-striped.table-bordered
  38 + %thead
  39 + %tr
  40 + %th Name
  41 + %th Project Access
  42 + %th Repository Access
  43 + %th
32 44  
  45 + - @admin_project.users_projects.each do |tm|
  46 + %tr
  47 + %td
  48 + = link_to tm.user_name, admin_user_path(tm.user)
  49 + %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), :class => "medium project-access-select", :disabled => :disabled
  50 + %td= link_to 'Edit Access', edit_admin_team_member_path(tm), :class => "btn small"
  51 + %td= link_to 'Remove from team', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete, :class => "btn danger small"
33 52  
34   -.span12
35   -
36   - %h3
37   - Team
38   - %small
39   - (#{@admin_project.users_projects.count})
40   -
41   - %hr
42   -
43   - %table.zebra-striped
  53 +%br
  54 +%h3 Add new team member
  55 +%br
  56 += form_tag team_update_admin_project_path(@admin_project), :class => "bulk_import", :method => :put do
  57 + %table.zebra-striped.table-bordered
44 58 %thead
45 59 %tr
46   - %th Name
47   - %th Project Access
48   - %th Repository Access
49   - %th
  60 + %th Users
  61 + %th Project Access:
50 62  
51   - - @admin_project.users_projects.each do |tm|
52   - %tr
53   - %td
54   - = link_to tm.user_name, admin_user_path(tm.user)
55   - %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), :class => "medium project-access-select", :disabled => :disabled
56   - %td= link_to 'Edit Access', edit_admin_team_member_path(tm), :class => "btn small"
57   - %td= link_to 'Remove from team', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete, :class => "btn danger small"
58   -
59   - = form_tag team_update_admin_project_path(@admin_project), :class => "bulk_import", :method => :put do
60   - %table
61   - %thead
62   - %tr
63   - %th Users
64   - %th Project Access:
65   - %th Repo Access:
66   -
67   - %tr
68   - %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), :multiple => true
69   - %td= select_tag :project_access, options_for_select(Project.access_options), :class => "project-access-select"
  63 + %tr
  64 + %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), :multiple => true
  65 + %td= select_tag :project_access, options_for_select(Project.access_options), :class => "project-access-select"
70 66  
71   - .actions
72   - = submit_tag 'Add', :class => "btn primary"
  67 + %tr
  68 + %td= submit_tag 'Add', :class => "btn primary"
  69 + %td
  70 + Read more about project permissions
  71 + %strong= link_to "here", help_permissions_path, :class => "vlink"
73 72  
74 73 :css
75 74 form select {
... ...
app/views/admin/users/_form.html.haml
... ... @@ -6,41 +6,55 @@
6 6 - @admin_user.errors.full_messages.each do |msg|
7 7 %li= msg
8 8  
9   - .clearfix
10   - = f.label :name
11   - .input= f.text_field :name
12   - .clearfix
13   - = f.label :email
14   - .input= f.text_field :email
15   - .clearfix
16   - = f.label :password
17   - .input= f.password_field :password
18   - .clearfix
19   - = f.label :password_confirmation
20   - .input= f.password_field :password_confirmation
  9 + .row
  10 + .span6
  11 + .clearfix
  12 + = f.label :name
  13 + .input
  14 + = f.text_field :name
  15 + %span.help-inline * requried
  16 + .clearfix
  17 + = f.label :email
  18 + .input
  19 + = f.text_field :email
  20 + %span.help-inline * requried
  21 + .clearfix
  22 + = f.label :password
  23 + .input= f.password_field :password
  24 + .clearfix
  25 + = f.label :password_confirmation
  26 + .input= f.password_field :password_confirmation
  27 + %hr
  28 + .clearfix
  29 + = f.label :skype
  30 + .input= f.text_field :skype
  31 + .clearfix
  32 + = f.label :linkedin
  33 + .input= f.text_field :linkedin
  34 + .clearfix
  35 + = f.label :twitter
  36 + .input= f.text_field :twitter
  37 + .span6
  38 + .clearfix
  39 + = f.label :projects_limit
  40 + .input= f.text_field :projects_limit, :class => "small_input"
21 41  
22   - .clearfix
23   - = f.label :projects_limit
24   - .input= f.text_field :projects_limit, :class => "small_input"
25   -
26   - .clearfix
27   - = f.label :skype
28   - .input= f.text_field :skype
29   - .clearfix
30   - = f.label :linkedin
31   - .input= f.text_field :linkedin
32   - .clearfix
33   - = f.label :twitter
34   - .input= f.text_field :twitter
35   - %hr
36   - .clearfix
37   - = f.label :admin do
38   - = f.check_box :admin
39   - %span Administrator
40   - .clearfix
41   - = f.label :blocked do
42   - = f.check_box :blocked
43   - %span Blocked
  42 + .alert
  43 + .clearfix
  44 + %p Give user ability to manage application.
  45 + = f.label :admin, :class => "checkbox" do
  46 + = f.check_box :admin
  47 + %span Administrator
  48 + - unless @admin_user.new_record?
  49 + .alert.alert-error
  50 + - if @admin_user.blocked
  51 + %span
  52 + = link_to 'Unblock', unblock_admin_user_path(@admin_user), :method => :put, :class => "btn small"
  53 + This user is blocked and is not able to login GitLab
  54 + - else
  55 + %span
  56 + = link_to 'Block', block_admin_user_path(@admin_user), :confirm => 'USER WILL BE BLOCKED! Are you sure?', :method => :put, :class => "btn small danger"
  57 + Blocked user will removed from all projects &amp; will not be able to login to GitLab.
44 58 .actions
45 59 = f.submit 'Save', :class => "btn primary"
46 60 - if @admin_user.new_record?
... ...
app/views/admin/users/index.html.haml
... ... @@ -2,15 +2,29 @@
2 2 Users
3 3 = link_to 'New User', new_admin_user_path, :class => "btn small right"
4 4 %br
5   -%table.zebra-striped.table-bordered
  5 +
  6 +%ul.nav.nav-pills
  7 + %li{:class => "#{'active' unless params[:filter]}"}
  8 + = link_to "Active", admin_users_path
  9 + %li{:class => "#{'active' if params[:filter] == "admins"}"}
  10 + = link_to admin_users_path(:filter => "admins") do
  11 + Admins
  12 + %li{:class => "#{'active' if params[:filter] == "blocked"}"}
  13 + = link_to admin_users_path(:filter => "blocked") do
  14 + Blocked
  15 + %li{:class => "#{'active' if params[:filter] == "wop"}"}
  16 + = link_to admin_users_path(:filter => "wop") do
  17 + Without projects
  18 +
  19 +%table.admin-table
6 20 %thead
7 21 %th Admin
8 22 %th Name
9 23 %th Email
10 24 %th Projects
  25 + %th Edit
11 26 %th Blocked
12 27 %th
13   - %th
14 28  
15 29 - @admin_users.each do |user|
16 30 %tr
... ... @@ -18,8 +32,12 @@
18 32 %td= link_to user.name, [:admin, user]
19 33 %td= user.email
20 34 %td= user.users_projects.count
21   - %td= check_box_tag "blocked", 1, user.blocked, :disabled => :disabled
22 35 %td= link_to 'Edit', edit_admin_user_path(user), :id => "edit_#{dom_id(user)}", :class => "btn small"
23   - %td= link_to 'Destroy', [:admin, user], :confirm => 'Are you sure?', :method => :delete, :class => "btn small danger"
  36 + %td
  37 + - if user.blocked
  38 + = link_to 'Unblock', unblock_admin_user_path(user), :method => :put, :class => "btn small success"
  39 + - else
  40 + = link_to 'Block', block_admin_user_path(user), :confirm => 'USER WILL BE BLOCKED! Are you sure?', :method => :put, :class => "btn small danger"
  41 + %td= link_to 'Destroy', [:admin, user], :confirm => 'USER WILL BE REMOVED! Are you sure?', :method => :delete, :class => "btn small danger"
24 42  
25 43 = paginate @admin_users, :theme => "admin"
... ...
app/views/admin/users/show.html.haml
1 1 %h3
2 2 = @admin_user.name
  3 + - if @admin_user.blocked
  4 + %small Blocked
  5 + - if @admin_user.admin
  6 + %small Administrator
3 7 = link_to 'Edit', edit_admin_user_path(@admin_user), :class => "btn small right"
4 8  
5   -%hr
  9 +%br
6 10  
7   -%table.zebra-striped
  11 +%table.zebra-striped.table-bordered
8 12 %tr
9 13 %td
10 14 %b
... ... @@ -49,41 +53,47 @@
49 53 %td
50 54 = @admin_user.twitter
51 55  
52   -%h3 Projects
53   -%hr
54   -
55   -%table.zebra-striped
56   - %tr
57   - %thead
58   - %th Name
59   - %th Project Access
60   - %th Repository Access
61   - %th
62   - %th
63   -
64   - - @admin_user.users_projects.each do |tm|
65   - - project = tm.project
66   - %tr
67   - %td= link_to project.name, admin_project_path(project)
68   - %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), :class => "medium project-access-select", :disabled => :disabled
69   - %td= link_to 'Edit Access', edit_admin_team_member_path(tm), :class => "btn small"
70   - %td= link_to 'Remove from team', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete, :class => "btn small danger"
71 56  
  57 +%br
  58 +%h3 Add User to Projects
  59 +%br
72 60 = form_tag team_update_admin_user_path(@admin_user), :class => "bulk_import", :method => :put do
73   - %table
  61 + %table.table-bordered
74 62 %thead
75 63 %tr
76 64 %th Projects
77 65 %th Project Access:
78   - %th Repo Access:
79 66  
80 67 %tr
81 68 %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name), :multiple => true
82 69 %td= select_tag :project_access, options_for_select(Project.access_options), :class => "project-access-select"
83 70  
84   - .actions
85   - = submit_tag 'Add', :class => "btn primary"
  71 + %tr
  72 + %td= submit_tag 'Add', :class => "btn primary"
  73 + %td
  74 + Read more about project permissions
  75 + %strong= link_to "here", help_permissions_path, :class => "vlink"
  76 +%br
  77 +
  78 +- if @admin_user.projects.present?
  79 + %h3 Projects
  80 + %br
86 81  
  82 + %table.zebra-striped.table-bordered
  83 + %tr
  84 + %thead
  85 + %th Name
  86 + %th Project Access
  87 + %th
  88 + %th
  89 +
  90 + - @admin_user.users_projects.each do |tm|
  91 + - project = tm.project
  92 + %tr
  93 + %td= link_to project.name, admin_project_path(project)
  94 + %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), :class => "medium project-access-select", :disabled => :disabled
  95 + %td= link_to 'Edit Access', edit_admin_team_member_path(tm), :class => "btn small"
  96 + %td= link_to 'Remove from team', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete, :class => "btn small danger"
87 97  
88 98 :css
89 99 form select {
... ...
app/views/help/index.html.haml
1 1 %h3
2 2 Gitlabhq
3   - %span.right v2.3
  3 + %span.right v2.4
4 4 %hr
5 5 %h4 Self Hosted Git Management
6 6 %h4 Fast, secure and stable solution based on Ruby on Rails & Gitolite.
... ...
app/views/layouts/admin.html.haml
... ... @@ -7,8 +7,8 @@
7 7 .container
8 8 %nav.main_menu
9 9 = render "layouts/const_menu_links"
10   - = link_to "Users", admin_users_path, :class => controller.controller_name == "users" ? "current" : nil
11 10 = link_to "Projects", admin_projects_path, :class => controller.controller_name == "projects" ? "current" : nil
  11 + = link_to "Users", admin_users_path, :class => controller.controller_name == "users" ? "current" : nil
12 12 = link_to "Emails", admin_emails_path, :class => controller.controller_name == "mailer" ? "current" : nil
13 13 = link_to "Resque", "/info/resque"
14 14  
... ...
config/routes.rb
... ... @@ -14,6 +14,8 @@ Gitlab::Application.routes.draw do
14 14 resources :users do
15 15 member do
16 16 put :team_update
  17 + put :block
  18 + put :unblock
17 19 end
18 20 end
19 21 resources :projects, :constraints => { :id => /[^\/]+/ } do
... ...