add split users api

fixes CNVS-27293

test plan
 - merge two users
 - split with api
 - it should return 2 users

Change-Id: I99bfb527374d995d3c50159c667ebe9c14cf84d2
Reviewed-on: https://gerrit.instructure.com/74012
Reviewed-by: Cody Cutrer <cody@instructure.com>
QA-Review: Jeremy Putnam <jeremyp@instructure.com>
Tested-by: Jenkins
Product-Review: Rob Orton <rob@instructure.com>
This commit is contained in:
Rob Orton 2016-03-25 12:16:06 -06:00
parent c40cbe2ca8
commit a7e547cd7d
3 changed files with 67 additions and 13 deletions

View File

@ -1803,7 +1803,9 @@ class UsersController < ApplicationController
# @API Merge user into another user
#
# Merge a user into another user.
# To merge users, the caller must have permissions to manage both users.
# To merge users, the caller must have permissions to manage both users. This
# should be considered irreversible. This will delete the user and move all
# the data into the destination user.
#
# When finding users by SIS ids in different accounts the
# destination_account_id is required.
@ -1845,6 +1847,39 @@ class UsersController < ApplicationController
end
end
# @API Split merged users into separate users
#
# Merged users cannot be fully restored to their previous state, but this will
# attempt to split as much as possible to the previous state.
# To split a merged user, the caller must have permissions to manage all of
# the users logins. If there are multiple users that have been merged into one
# user it will split each merge into a separate user.
# A split can only happen within 90 days of a user merge. A user merge deletes
# the previous user and may be permanently deleted. In this scenario we create
# a new user object and proceed to move as much as possible to the new user.
# The user object will not have preserved the name or settings from the
# previous user. Some items may have been deleted during a user_merge that
# cannot be restored, and/or the data has become stale because of other
# changes to the objects since the time of the user_merge.
#
# @example_request
# curl https://<canvas>/api/v1/users/<user_id>/split \
# -X POST \
# -H 'Authorization: Bearer <token>'
#
# @returns [User]
def split
user = api_find(User, params[:id])
unless UserMergeData.active.where(user_id: user).where('created_at > ?', 90.days.ago).exists?
return render json: {message: t('Nothing to split off of this user')}, status: :bad_request
end
if authorized_action(user, @current_user, :merge)
users = SplitUsers.split_db_users(user)
render :json => users.map { |u| user_json(u, @current_user, session) }
end
end
protected
def teacher_activity_report(teacher, course, student_enrollments)

View File

@ -1180,6 +1180,7 @@ CanvasRails::Application.routes.draw do
put 'users/:id/merge_into/:destination_user_id', controller: 'users', action: 'merge_into'
put 'users/:id/merge_into/accounts/:destination_account_id/users/:destination_user_id', controller: 'users', action: 'merge_into'
post 'users/:id/split', controller: 'users', action: 'split'
scope(controller: :user_observees) do
get 'users/:user_id/observees', action: :index, as: 'user_observees'

View File

@ -1352,7 +1352,7 @@ describe "Users API", type: :request do
end
end
describe "user merge" do
describe "user merge and split" do
before :once do
@account = Account.default
@user1 = user_with_managed_pseudonym(
@ -1366,17 +1366,23 @@ describe "Users API", type: :request do
@user = account_admin_user(account: @account)
end
it "should merge users" do
json = api_call(
it "should merge and split users" do
api_call(
:put, "/api/v1/users/#{@user2.id}/merge_into/#{@user1.id}",
{ controller: 'users', action: 'merge_into', format: 'json',
id: @user2.to_param, destination_user_id: @user1.to_param }
{controller: 'users', action: 'merge_into', format: 'json',
id: @user2.to_param, destination_user_id: @user1.to_param}
)
expect(Pseudonym.where(sis_user_id: 'user_sis_id_02').first.user_id).to eq @user1.id
expect(@user2.pseudonyms).to be_empty
api_call(
:post, "/api/v1/users/#{@user1.id}/split/",
{controller: 'users', action: 'split', format: 'json', id: @user1.to_param}
)
expect(Pseudonym.where(sis_user_id: 'user_sis_id_01').first.user_id).to eq @user1.id
expect(Pseudonym.where(sis_user_id: 'user_sis_id_02').first.user_id).to eq @user2.id
end
it "should merge users cross accounts" do
it "should merge and split users cross accounts" do
account = Account.create(name: 'new account')
@user1.pseudonym.account_id = account.id
@user1.pseudonym.save!
@ -1385,14 +1391,20 @@ describe "Users API", type: :request do
api_call(
:put,
"/api/v1/users/sis_user_id:user_sis_id_02/merge_into/accounts/#{account.id}/users/sis_user_id:user_sis_id_01",
{ controller: 'users', action: 'merge_into', format: 'json',
id: 'sis_user_id:user_sis_id_02',
destination_user_id: 'sis_user_id:user_sis_id_01',
destination_account_id: account.to_param
{controller: 'users', action: 'merge_into', format: 'json',
id: 'sis_user_id:user_sis_id_02',
destination_user_id: 'sis_user_id:user_sis_id_01',
destination_account_id: account.to_param
}
)
expect(Pseudonym.where(sis_user_id: 'user_sis_id_02').first.user_id).to eq @user1.id
expect(@user2.pseudonyms).to be_empty
api_call(
:post, "/api/v1/users/#{@user1.id}/split/",
{controller: 'users', action: 'split', format: 'json', id: @user1.to_param}
)
expect(Pseudonym.where(sis_user_id: 'user_sis_id_01').first.user_id).to eq @user1.id
expect(Pseudonym.where(sis_user_id: 'user_sis_id_02').first.user_id).to eq @user2.id
end
it "should fail to merge users cross accounts without permissions" do
@ -1403,11 +1415,17 @@ describe "Users API", type: :request do
raw_api_call(
:put,
"/api/v1/users/#{@user2.id}/merge_into/#{@user1.id}",
{ controller: 'users', action: 'merge_into', format: 'json',
id: @user2.to_param, destination_user_id: @user1.to_param}
{controller: 'users', action: 'merge_into', format: 'json',
id: @user2.to_param, destination_user_id: @user1.to_param}
)
assert_status(401)
end
it "should fail to split users that have not been merged" do
raw_api_call(:post, "/api/v1/users/#{@user2.id}/split/",
{controller: 'users', action: 'split', format: 'json', id: @user2.to_param})
assert_status(400)
end
end
describe 'Custom Colors' do