Commit 6b16f8a7a84a91bafac97e1e7e2390e32877eabb
Exists in
master
and in
4 other branches
Merge branch 'improve/user_removal' of /home/git/repositories/gitlab/gitlabhq
Showing
10 changed files
with
77 additions
and
40 deletions
Show diff stats
app/assets/javascripts/admin.js.coffee
@@ -23,10 +23,16 @@ class Admin | @@ -23,10 +23,16 @@ class Admin | ||
23 | e.preventDefault() | 23 | e.preventDefault() |
24 | $(this).hide() | 24 | $(this).hide() |
25 | modal.show() | 25 | modal.show() |
26 | - | 26 | + |
27 | $('.change-owner-cancel-link').bind "click", (e) -> | 27 | $('.change-owner-cancel-link').bind "click", (e) -> |
28 | e.preventDefault() | 28 | e.preventDefault() |
29 | modal.hide() | 29 | modal.hide() |
30 | $('.change-owner-link').show() | 30 | $('.change-owner-link').show() |
31 | 31 | ||
32 | + $('li.users_project').bind 'ajax:success', -> | ||
33 | + Turbolinks.visit(location.href) | ||
34 | + | ||
35 | + $('li.users_group').bind 'ajax:success', -> | ||
36 | + Turbolinks.visit(location.href) | ||
37 | + | ||
32 | @Admin = Admin | 38 | @Admin = Admin |
app/controllers/admin/members_controller.rb
@@ -1,9 +0,0 @@ | @@ -1,9 +0,0 @@ | ||
1 | -class Admin::MembersController < Admin::ApplicationController | ||
2 | - def destroy | ||
3 | - user = User.find_by_username(params[:id]) | ||
4 | - project = Project.find_with_namespace(params[:project_id]) | ||
5 | - project.users_projects.where(user_id: user).first.destroy | ||
6 | - | ||
7 | - redirect_to :back | ||
8 | - end | ||
9 | -end |
app/controllers/admin/users_controller.rb
@@ -83,9 +83,10 @@ class Admin::UsersController < Admin::ApplicationController | @@ -83,9 +83,10 @@ class Admin::UsersController < Admin::ApplicationController | ||
83 | end | 83 | end |
84 | 84 | ||
85 | def destroy | 85 | def destroy |
86 | - if user.personal_projects.count > 0 | ||
87 | - redirect_to admin_users_path, alert: "User is a project owner and can't be removed." and return | ||
88 | - end | 86 | + # 1. Remove groups where user is the only owner |
87 | + user.solo_owned_groups.map(&:destroy) | ||
88 | + | ||
89 | + # 2. Remove user with all authored content including personal projects | ||
89 | user.destroy | 90 | user.destroy |
90 | 91 | ||
91 | respond_to do |format| | 92 | respond_to do |format| |
app/models/group.rb
@@ -23,7 +23,7 @@ class Group < Namespace | @@ -23,7 +23,7 @@ class Group < Namespace | ||
23 | end | 23 | end |
24 | 24 | ||
25 | def owners | 25 | def owners |
26 | - @owners ||= (users_groups.owners.map(&:user) << owner) | 26 | + @owners ||= (users_groups.owners.map(&:user) << owner).uniq |
27 | end | 27 | end |
28 | 28 | ||
29 | def add_users(user_ids, group_access) | 29 | def add_users(user_ids, group_access) |
app/models/project_team.rb
@@ -32,7 +32,15 @@ class ProjectTeam | @@ -32,7 +32,15 @@ class ProjectTeam | ||
32 | end | 32 | end |
33 | 33 | ||
34 | def find_tm(user_id) | 34 | def find_tm(user_id) |
35 | - project.users_projects.find_by_user_id(user_id) | 35 | + tm = project.users_projects.find_by_user_id(user_id) |
36 | + | ||
37 | + # If user is not in project members | ||
38 | + # we should check for group membership | ||
39 | + if group && !tm | ||
40 | + tm = group.users_groups.find_by_user_id(user_id) | ||
41 | + end | ||
42 | + | ||
43 | + tm | ||
36 | end | 44 | end |
37 | 45 | ||
38 | def add_user(user, access) | 46 | def add_user(user, access) |
app/models/user.rb
@@ -135,7 +135,7 @@ class User < ActiveRecord::Base | @@ -135,7 +135,7 @@ class User < ActiveRecord::Base | ||
135 | # Remove user from all groups | 135 | # Remove user from all groups |
136 | user.users_groups.find_each do |membership| | 136 | user.users_groups.find_each do |membership| |
137 | # skip owned resources | 137 | # skip owned resources |
138 | - next if membership.group.owner == user | 138 | + next if membership.group.owners.include?(user) |
139 | 139 | ||
140 | return false unless membership.destroy | 140 | return false unless membership.destroy |
141 | end | 141 | end |
@@ -376,4 +376,10 @@ class User < ActiveRecord::Base | @@ -376,4 +376,10 @@ class User < ActiveRecord::Base | ||
376 | self.send("#{attr}=", Sanitize.clean(value)) if value.present? | 376 | self.send("#{attr}=", Sanitize.clean(value)) if value.present? |
377 | end | 377 | end |
378 | end | 378 | end |
379 | + | ||
380 | + def solo_owned_groups | ||
381 | + @solo_owned_groups ||= owned_groups.select do |group| | ||
382 | + group.owners == [self] | ||
383 | + end | ||
384 | + end | ||
379 | end | 385 | end |
app/views/admin/users/show.html.haml
@@ -7,15 +7,11 @@ | @@ -7,15 +7,11 @@ | ||
7 | %span.cred (Admin) | 7 | %span.cred (Admin) |
8 | 8 | ||
9 | .pull-right | 9 | .pull-right |
10 | - = link_to edit_admin_user_path(@user), class: "btn grouped btn-small" do | 10 | + = link_to edit_admin_user_path(@user), class: "btn grouped" do |
11 | %i.icon-edit | 11 | %i.icon-edit |
12 | Edit | 12 | Edit |
13 | - - unless @user == current_user | ||
14 | - - if @user.blocked? | ||
15 | - = link_to 'Unblock', unblock_admin_user_path(@user), method: :put, class: "btn grouped btn-small success" | ||
16 | - - else | ||
17 | - = link_to 'Block', block_admin_user_path(@user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn grouped btn-small btn-remove" | ||
18 | - = link_to 'Destroy', [:admin, @user], confirm: "USER #{@user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn grouped btn-small btn-remove" | 13 | + - if @user.blocked? |
14 | + = link_to 'Unblock', unblock_admin_user_path(@user), method: :put, class: "btn grouped success" | ||
19 | %hr | 15 | %hr |
20 | 16 | ||
21 | .row | 17 | .row |
@@ -63,24 +59,56 @@ | @@ -63,24 +59,56 @@ | ||
63 | %strong | 59 | %strong |
64 | = link_to @user.created_by.name, [:admin, @user.created_by] | 60 | = link_to @user.created_by.name, [:admin, @user.created_by] |
65 | 61 | ||
62 | + - unless @user == current_user | ||
63 | + .alert | ||
64 | + %h4 Block user | ||
65 | + %br | ||
66 | + %p Blocking user has the following effects: | ||
67 | + %ul | ||
68 | + %li User will not be able to login | ||
69 | + %li User will not be able to access git repositories | ||
70 | + %li User will be removed from joined projects and groups | ||
71 | + %li Personal projects will be left | ||
72 | + %li Owned groups will be left | ||
73 | + = link_to 'Block user', block_admin_user_path(@user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-remove" | ||
74 | + | ||
75 | + .alert.alert-error | ||
76 | + %h4 | ||
77 | + Remove user | ||
78 | + %br | ||
79 | + %p Deleting a user has the following effects: | ||
80 | + %ul | ||
81 | + %li All user content like authored issues, snippets, comments will be removed | ||
82 | + - rp = @user.personal_projects.count | ||
83 | + - unless rp.zero? | ||
84 | + %li #{pluralize rp, 'personal project'} will be removed and cannot be restored | ||
85 | + - if @user.solo_owned_groups.present? | ||
86 | + %li | ||
87 | + Next groups with all content will be removed: | ||
88 | + %strong #{@user.solo_owned_groups.map(&:name).join(', ')} | ||
89 | + = link_to 'Remove user', [:admin, @user], confirm: "USER #{@user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn btn-remove" | ||
90 | + | ||
91 | + .span6 | ||
66 | - if @user.users_groups.present? | 92 | - if @user.users_groups.present? |
67 | .ui-box | 93 | .ui-box |
68 | .title Groups: | 94 | .title Groups: |
69 | %ul.well-list | 95 | %ul.well-list |
70 | - @user.users_groups.each do |user_group| | 96 | - @user.users_groups.each do |user_group| |
71 | - group = user_group.group | 97 | - group = user_group.group |
72 | - %li | 98 | + %li.users_group |
73 | %strong= link_to group.name, admin_group_path(group) | 99 | %strong= link_to group.name, admin_group_path(group) |
74 | .pull-right | 100 | .pull-right |
75 | %span.light= user_group.human_access | 101 | %span.light= user_group.human_access |
102 | + - unless user_group.owner? | ||
103 | + = link_to group_users_group_path(group, user_group), confirm: remove_user_from_group_message(group, @user), method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do | ||
104 | + %i.icon-remove.icon-white | ||
76 | 105 | ||
77 | - .span6 | ||
78 | .ui-box | 106 | .ui-box |
79 | .title Projects (#{@projects.count}) | 107 | .title Projects (#{@projects.count}) |
80 | %ul.well-list | 108 | %ul.well-list |
81 | - @projects.sort_by(&:name_with_namespace).each do |project| | 109 | - @projects.sort_by(&:name_with_namespace).each do |project| |
82 | - tm = project.team.find_tm(@user.id) | 110 | - tm = project.team.find_tm(@user.id) |
83 | - %li | 111 | + %li.users_project |
84 | = link_to admin_project_path(project), class: dom_class(project) do | 112 | = link_to admin_project_path(project), class: dom_class(project) do |
85 | - if project.namespace | 113 | - if project.namespace |
86 | = project.namespace.human_name | 114 | = project.namespace.human_name |
@@ -94,5 +122,9 @@ | @@ -94,5 +122,9 @@ | ||
94 | %span.light Owner | 122 | %span.light Owner |
95 | - else | 123 | - else |
96 | %span.light= tm.human_access | 124 | %span.light= tm.human_access |
97 | - = link_to admin_project_member_path(project, tm.user), confirm: remove_from_project_team_message(project, @user), method: :delete, class: "btn btn-small btn-remove" do | ||
98 | - %i.icon-remove | 125 | + |
126 | + - if tm.respond_to? :project | ||
127 | + = link_to project_team_member_path(project, @user), confirm: remove_from_project_team_message(project, @user), remote: true, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from project' do | ||
128 | + %i.icon-remove | ||
129 | + | ||
130 | + |
config/routes.rb
@@ -89,11 +89,7 @@ Gitlab::Application.routes.draw do | @@ -89,11 +89,7 @@ Gitlab::Application.routes.draw do | ||
89 | 89 | ||
90 | resource :logs, only: [:show] | 90 | resource :logs, only: [:show] |
91 | resource :background_jobs, controller: 'background_jobs', only: [:show] | 91 | resource :background_jobs, controller: 'background_jobs', only: [:show] |
92 | - | ||
93 | - resources :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }, only: [:index, :show] do | ||
94 | - resources :members, only: [:destroy] | ||
95 | - end | ||
96 | - | 92 | + resources :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }, only: [:index, :show] |
97 | root to: "dashboard#index" | 93 | root to: "dashboard#index" |
98 | end | 94 | end |
99 | 95 |
lib/gitlab/access.rb
@@ -44,5 +44,9 @@ module Gitlab | @@ -44,5 +44,9 @@ module Gitlab | ||
44 | def human_access | 44 | def human_access |
45 | Gitlab::Access.options_with_owner.key(access_field) | 45 | Gitlab::Access.options_with_owner.key(access_field) |
46 | end | 46 | end |
47 | + | ||
48 | + def owner? | ||
49 | + access_field == OWNER | ||
50 | + end | ||
47 | end | 51 | end |
48 | end | 52 | end |
spec/routing/admin_routing_spec.rb
@@ -75,13 +75,6 @@ describe Admin::ProjectsController, "routing" do | @@ -75,13 +75,6 @@ describe Admin::ProjectsController, "routing" do | ||
75 | end | 75 | end |
76 | end | 76 | end |
77 | 77 | ||
78 | -# DELETE /admin/projects/:project_id/members/:id(.:format) admin/projects/members#destroy {id: /[^\/]+/, project_id: /[^\/]+/} | ||
79 | -describe Admin::MembersController, "routing" do | ||
80 | - it "to #destroy" do | ||
81 | - delete("/admin/projects/test/members/1").should route_to('admin/members#destroy', project_id: 'test', id: '1') | ||
82 | - end | ||
83 | -end | ||
84 | - | ||
85 | # admin_hook_test GET /admin/hooks/:hook_id/test(.:format) admin/hooks#test | 78 | # admin_hook_test GET /admin/hooks/:hook_id/test(.:format) admin/hooks#test |
86 | # admin_hooks GET /admin/hooks(.:format) admin/hooks#index | 79 | # admin_hooks GET /admin/hooks(.:format) admin/hooks#index |
87 | # POST /admin/hooks(.:format) admin/hooks#create | 80 | # POST /admin/hooks(.:format) admin/hooks#create |