Skip to content

Commit

Permalink
Enable ability for administrators to delete users (#7296).
Browse files Browse the repository at this point in the history
User's personal data (eg. preferences, tokens, private queries...) are deleted, public data (eg. issues, wiki edits, attachments...) are reassigned to the anonymous user.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4729 e93f8b46-1217-0410-a6f0-8f06a7374b81
  • Loading branch information
jplang committed Jan 16, 2011
1 parent 0e3017d commit e9f62d1
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 20 deletions.
13 changes: 11 additions & 2 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ class UsersController < ApplicationController
layout 'admin'

before_filter :require_admin, :except => :show
before_filter :find_user, :only => [:show, :edit, :update, :edit_membership, :destroy_membership]
accept_key_auth :index, :show, :create, :update
before_filter :find_user, :only => [:show, :edit, :update, :destroy, :edit_membership, :destroy_membership]
accept_key_auth :index, :show, :create, :update, :destroy

helper :sort
include SortHelper
Expand Down Expand Up @@ -177,6 +177,15 @@ def update
redirect_to :controller => 'users', :action => 'edit', :id => @user
end

verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed }
def destroy
@user.destroy
respond_to do |format|
format.html { redirect_to(users_url) }
format.api { head :ok }
end
end

def edit_membership
@membership = Member.edit_membership(params[:membership_id], params[:membership], @user)
@membership.save if request.post?
Expand Down
1 change: 1 addition & 0 deletions app/views/users/edit.rhtml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<div class="contextual">
<%= link_to l(:label_profile), user_path(@user), :class => 'icon icon-user' %>
<%= change_status_link(@user) %>
<%= link_to(l(:button_delete), @user, :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del') if User.current != @user %>
</div>

<h2><%= link_to l(:label_user_plural), :controller => 'users', :action => 'index' %> &#187; <%=h @user.login %></h2>
Expand Down
5 changes: 4 additions & 1 deletion app/views/users/index.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@
<td align="center"><%= checked_image user.admin? %></td>
<td class="created_on" align="center"><%= format_time(user.created_on) %></td>
<td class="last_login_on" align="center"><%= format_time(user.last_login_on) unless user.last_login_on.nil? %></td>
<td><small><%= change_status_link(user) %></small></td>
<td class="buttons">
<%= change_status_link(user) %>
<%= link_to(l(:button_delete), user, :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del') unless User.current == user %>
</td>
</tr>
<% end -%>
</tbody>
Expand Down
3 changes: 1 addition & 2 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,7 @@
map.resources :users, :member => {
:edit_membership => :post,
:destroy_membership => :post
},
:except => [:destroy]
}

# For nice "roadmap" in the url for the index action
map.connect 'projects/:project_id/roadmap', :controller => 'versions', :action => 'index'
Expand Down
24 changes: 24 additions & 0 deletions test/functional/users_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,30 @@ def test_update_with_password_change_should_send_a_notification
assert u.check_password?('newpass')
end

def test_destroy
assert_difference 'User.count', -1 do
delete :destroy, :id => 2
end
assert_redirected_to '/users'
assert_nil User.find_by_id(2)
end

def test_destroy_should_not_accept_get_requests
assert_no_difference 'User.count' do
get :destroy, :id => 2
end
assert_response 405
end

def test_destroy_should_be_denied_for_non_admin_users
@request.session[:user_id] = 3

assert_no_difference 'User.count' do
get :destroy, :id => 2
end
assert_response 403
end

def test_edit_membership
post :edit_membership, :id => 2, :membership_id => 1,
:membership => { :role_ids => [2]}
Expand Down
40 changes: 25 additions & 15 deletions test/integration/api_test/users_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -245,26 +245,36 @@ def setup
end
end
end
end

context "DELETE /users/2" do
context ".xml" do
should "not be allowed" do
assert_no_difference('User.count') do
delete '/users/2.xml'
end

assert_response :method_not_allowed
context "DELETE /users/2" do
context ".xml" do
should_allow_api_authentication(:delete,
'/users/2.xml',
{},
{:success_code => :ok})

should "delete user" do
assert_difference('User.count', -1) do
delete '/users/2.xml', {}, :authorization => credentials('admin')
end

assert_response :ok
end

context ".json" do
should "not be allowed" do
assert_no_difference('User.count') do
delete '/users/2.json'
end
end

context ".json" do
should_allow_api_authentication(:delete,
'/users/2.xml',
{},
{:success_code => :ok})

assert_response :method_not_allowed
should "delete user" do
assert_difference('User.count', -1) do
delete '/users/2.json', {}, :authorization => credentials('admin')
end

assert_response :ok
end
end
end
Expand Down
3 changes: 3 additions & 0 deletions test/integration/routing_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,9 @@ class RoutingTest < ActionController::IntegrationTest

should_route :put, "/users/444", :controller => 'users', :action => 'update', :id => '444'
should_route :put, "/users/444.xml", :controller => 'users', :action => 'update', :id => '444', :format => 'xml'

should_route :delete, "/users/44", :controller => 'users', :action => 'destroy', :id => '44'
should_route :delete, "/users/44.xml", :controller => 'users', :action => 'destroy', :id => '44', :format => 'xml'
end

# TODO: should they all be scoped under /projects/:project_id ?
Expand Down

0 comments on commit e9f62d1

Please sign in to comment.