Merge pull request #2331 from opf/feature/api_v3_delete_user

17654 delete user
pull/2348/head
Alex Coles 10 years ago
commit ee8c557901
  1. 17
      app/controllers/users_controller.rb
  2. 78
      app/services/delete_user_service.rb
  3. 44
      app/workers/delete_user_job.rb
  4. 7
      lib/api/v3/users/users_api.rb
  5. 95
      spec/requests/api/v3/user_resource_spec.rb

@ -269,16 +269,7 @@ class UsersController < ApplicationController
# true if the user deletes him/herself
self_delete = (@user == User.current)
# as destroying users is a lengthy process we handle it in the background
# and lock the account now so that no action can be performed with it
@user.status = User::STATUSES[:locked]
@user.save
@user.delay.destroy
# log the user out if it's a self-delete
# must be called before setting the flash message
self.logged_user = nil if self_delete
DeleteUserService.new(@user, User.current).call
flash[:notice] = l('account.deleted')
@ -339,11 +330,7 @@ class UsersController < ApplicationController
end
def check_if_deletion_allowed
if (User.current.admin && @user != User.current && !Setting.users_deletable_by_admins?) ||
(User.current == @user && !Setting.users_deletable_by_self?)
render_404
false
end
render_404 unless DeleteUserService.deletion_allowed? @user, User.current
end
def my_or_admin_layout

@ -0,0 +1,78 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
##
# Implements the deletion of a user.
class DeleteUserService < Struct.new :user, :actor
##
# Deletes the given user if allowed.
#
# @return True if the user deletion has been initiated, false otherwise.
def call
if deletion_allowed?
# as destroying users is a lengthy process we handle it in the background
# and lock the account now so that no action can be performed with it
user.lock!
Delayed::Job.enqueue DeleteUserJob.new(user)
logout! if self_delete?
true
else
false
end
end
##
# Checks if a given user may be deleted by another one.
#
# @param user [User] User to be deleted.
# @param actor [User] User who wants to delete the given user.
def self.deletion_allowed?(user, actor)
if actor == user
Setting.users_deletable_by_self?
else
actor.admin && Setting.users_deletable_by_admins?
end
end
private
def deletion_allowed?
self.class.deletion_allowed? user, actor
end
def self_delete?
user == actor
end
def logout!
User.current = nil
end
end

@ -0,0 +1,44 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
class DeleteUserJob
def initialize(user)
@user_id = user.id
end
def perform
user.destroy
end
private
def user
@user ||= User.find @user_id
end
end

@ -45,6 +45,13 @@ module API
UserRepresenter.new(@user)
end
delete do
if DeleteUserService.new(@user, User.current).call
status 202
else
fail ::API::Errors::Unauthorized
end
end
end
end

@ -66,4 +66,99 @@ describe 'API v3 User resource', type: :request do
let(:id) { user.id }
end
end
describe '#delete' do
let(:path) { "/api/v3/users/#{user.id}" }
let(:admin_delete) { true }
let(:self_delete) { true }
before do
allow(User).to receive(:current).and_return current_user
allow(Setting).to receive(:users_deletable_by_admins?).and_return(admin_delete)
allow(Setting).to receive(:users_deletable_by_self?).and_return(self_delete)
delete path
end
subject(:response) { last_response }
shared_examples 'deletion through allowed user' do
it 'should respond with 202' do
expect(subject.status).to eq 202
end
it 'should delete the account' do
expect(User.exists?(user.id)).not_to be_true
end
context 'with a non-existent user' do
let(:path) { '/api/v3/users/1337' }
it_behaves_like 'not found', 1337, 'User'
end
context 'with non-admin user' do
let(:current_user) { FactoryGirl.create :user, admin: false }
it 'responds with 403' do
expect(subject.status).to eq 403
end
end
end
shared_examples 'deletion is not allowed' do
it 'should respond with 403' do
expect(subject.status).to eq 403
end
it 'should not delete the user' do
expect(User.exists?(user.id)).to be_true
end
end
context 'as admin' do
let(:current_user) { FactoryGirl.create :admin }
context 'with users deletable by admins' do
let(:admin_delete) { true }
it_behaves_like 'deletion through allowed user'
end
context 'with users not deletable by admins' do
let(:admin_delete) { false }
it_behaves_like 'deletion is not allowed'
end
end
context 'as non-admin' do
let(:current_user) { FactoryGirl.create :user, admin: false }
it_behaves_like 'deletion is not allowed'
end
context 'as self' do
let(:current_user) { user }
context 'with self-deletion allowed' do
let(:self_delete) { true }
it_behaves_like 'deletion through allowed user'
end
context 'with self-deletion not allowed' do
let(:self_delete) { false }
it_behaves_like 'deletion is not allowed'
end
end
context 'as anonymous user' do
let(:current_user) { FactoryGirl.create :anonymous }
it_behaves_like 'deletion is not allowed'
end
end
end

Loading…
Cancel
Save