

月末に 5 人が退職すると人事から連絡を受けたとします。退職の連絡を受けた時点でユーザを[削除予定]にし、退職日を過ぎてから削除します。この記事では、この 2 段階を REST API で行う方法を説明します。
削除と[削除予定]の違いは、元に戻せるかと、進行中のケースを処理できるかの 2 点です。 [削除予定]は設定を外せば元に戻せ、ユーザが残るので進行中のケースもそのまま処理できます。削除したユーザは同じ ID では元に戻せず、そのユーザを参照している工程にケースが進んだときに、実行が失敗する可能性があります。どちらの場合も、処理担当者の設定などでそのユーザを参照しているアプリは、アプリ設定エラーになります。
[削除予定]にしてから削除するまでの間に、アプリ管理者にアプリ設定の修正を依頼し、そのユーザが持っているタスクを引き継ぎます。画面での段取りは「アプリに影響を与えない、安全なユーザ削除の仕方」で説明しています。
[削除予定]の設定も削除も、[システム設定]>[ユーザ一覧]からユーザごとに行えます。REST API を使うのは、この作業が毎月くり返される場合です。人事システムから届く退職者の CSV をそのまま使えるようにしておけば、次回からは CSV を差し替えて実行するだけで済みます。
コード例は Python 3 で、HTTP リクエストの送信に Requests パッケージを使います。[削除予定]にするスクリプトと、削除するスクリプトの 2 本に分け、どちらも「API を呼び出す準備」のコードに続けて書きます。末尾の「コード全体」に、2 本それぞれをまとめています。
用意する CSV
退職者の CSV は、メールアドレスの列だけで足ります。次の形で用意し、leavers.csv として保存します。
email
dylan.thomas@example.com
emily.dickinson@example.comAPI でユーザを探すには、メールアドレスを使います。ユーザ名には同姓同名があり得るためです。
この CSV は、[削除予定]にするときと削除するときの両方で使います。 退職の連絡を受けた時点で用意し、退職日を過ぎたら同じものをもう一度使います。
API を呼び出す準備
実行するユーザには、ユーザ管理権限と、Basic 認証による API アクセスの許可が必要です。 設定の手順と API パスワードの調べ方は、「System Settings REST API で入社と異動を反映する」の「API を呼び出す準備」と同じです。
接続先と認証情報を、次のように用意しておきます。
import csv
import requests
from requests.auth import HTTPBasicAuth
BASE = 'https://example.questetra.net'
AUTH = HTTPBasicAuth('admin@example.com', '{API パスワード}')
API の呼び出しは、次の関数を通します。 失敗したときは、応答本文を出力してから止めます。応答本文の読み方も、同じ記事の「API を呼び出す準備」で説明しています。
def check(r):
if not r.ok:
print(r.status_code, r.text)
r.raise_for_status()
return r
def call(method, path, **kwargs):
return check(requests.request(method, f'{BASE}{path}', auth=AUTH, **kwargs))
退職の連絡時:[削除予定]の設定
実行する前に、アプリ設定エラーが出ることをアプリ管理者に伝えてください。 [削除予定]にした時点で、そのユーザを参照しているアプリはアプリ設定エラーになります。
[削除予定]は、/API/UGA/Quser/update の deletedInFuture で設定します。この API はユーザ ID を必須とするため、メールアドレスから ID を引いてから更新します。
with open('leavers.csv', encoding='utf-8') as f:
for row in csv.DictReader(f):
found = requests.get(f'{BASE}/API/User/Quser/find', auth=AUTH,
params={'email': row['email']})
if found.status_code != 400:
check(found)
if not found.ok:
print(row['email'], '見つかりません')
continue
call('POST', '/API/UGA/Quser/update',
data={'id': found.json()['quser']['id'], 'deletedInFuture': 'true'})
print(row['email'], '削除予定にしました')
find は、未登録のメールアドレスには 400 を返します。 それだけを「見つからない」として扱い、認証エラーなどほかのエラーは check で止めます。call を通さないのはそのためです。
update は、指定しなかった項目を変更しません。ここでは deletedInFuture だけを渡しているので、ユーザ名やメールアドレス、所属はそのまま残ります。
退職日後:CSV からの削除
削除も、[削除予定]にしたときと同じ CSV から行います。 ワークフロー基盤は退職日を持っていません。[削除予定]で絞り込んで削除すると、退職日がまだ来ていない人や、別の担当者が別の理由で[削除予定]にしたユーザまで消してしまいます。その月の退職者の CSV を使えば、対象を取り違えません。
with open('leavers.csv', encoding='utf-8') as f:
for row in csv.DictReader(f):
found = requests.get(f'{BASE}/API/User/Quser/find', auth=AUTH,
params={'email': row['email']})
if found.status_code != 400:
check(found)
if not found.ok:
print(row['email'], '見つかりません')
continue
quser = found.json()['quser']
if not quser['deletedInFuture']:
print(row['email'], '削除予定になっていません')
continue
call('POST', '/API/UGA/Quser/delete', data={'id': quser['id']})
print(row['email'], '削除しました')
削除したユーザは元に戻せません。 実行するのは、アプリ設定の修正と、残っているタスクの引き継ぎが済んでからです。
[削除予定]になっていないユーザは、削除せずに書き出します。 [削除予定]にする手順を飛ばした人や、いったん取り消された人が、CSV に残っていることがあるためです。
削除し残しの確認
[削除予定]のまま残っているユーザは、deletedInFuture で絞り込んだ一覧で確認できます。一覧を返す API は、1 回の呼び出しで返る件数に上限があります。limit で 1 回あたりの件数を指定し、start をずらしながら、返ってきた件数が limit より少なくなるまでくり返します。
LIMIT = 10
start = 0
while True:
r = call('GET', '/API/User/Quser/list',
params={'deletedInFuture': 'true', 'start': start, 'limit': LIMIT})
qusers = r.json()['qusers']
for u in qusers:
print(u['id'], u['name'], u['email'])
if len(qusers) < LIMIT:
break
start += LIMIT
この一覧には、退職日がまだ来ていない人も、別の担当者が別の理由で[削除予定]にしたユーザも並びます。削除してよいかどうかは、この一覧からは判断できません。 退職者の CSV と突き合わせて、消し忘れがないかを見るために使います。
コード全体
[削除予定]にするスクリプトです。実行する前に、次の「実行の進め方」を読んでください。
import csv
import requests
from requests.auth import HTTPBasicAuth
BASE = 'https://example.questetra.net'
AUTH = HTTPBasicAuth('admin@example.com', '{API パスワード}')
def check(r):
if not r.ok:
print(r.status_code, r.text)
r.raise_for_status()
return r
def call(method, path, **kwargs):
return check(requests.request(method, f'{BASE}{path}', auth=AUTH, **kwargs))
with open('leavers.csv', encoding='utf-8') as f:
for row in csv.DictReader(f):
found = requests.get(f'{BASE}/API/User/Quser/find', auth=AUTH,
params={'email': row['email']})
if found.status_code != 400:
check(found)
if not found.ok:
print(row['email'], '見つかりません')
continue
call('POST', '/API/UGA/Quser/update',
data={'id': found.json()['quser']['id'], 'deletedInFuture': 'true'})
print(row['email'], '削除予定にしました')
削除するスクリプトです。
import csv
import requests
from requests.auth import HTTPBasicAuth
BASE = 'https://example.questetra.net'
AUTH = HTTPBasicAuth('admin@example.com', '{API パスワード}')
def check(r):
if not r.ok:
print(r.status_code, r.text)
r.raise_for_status()
return r
def call(method, path, **kwargs):
return check(requests.request(method, f'{BASE}{path}', auth=AUTH, **kwargs))
with open('leavers.csv', encoding='utf-8') as f:
for row in csv.DictReader(f):
found = requests.get(f'{BASE}/API/User/Quser/find', auth=AUTH,
params={'email': row['email']})
if found.status_code != 400:
check(found)
if not found.ok:
print(row['email'], '見つかりません')
continue
quser = found.json()['quser']
if not quser['deletedInFuture']:
print(row['email'], '削除予定になっていません')
continue
call('POST', '/API/UGA/Quser/delete', data={'id': quser['id']})
print(row['email'], '削除しました')
実行の進め方
まず 1 行だけの CSV で実行し、[システム設定]>[ユーザ一覧]で、そのユーザが[削除予定]になっていることを確認してください。 POST の API は、ワークフロー基盤のデータをその場で書き換えます。確認できてから、残りの行を流します。
削除するスクリプトも、同じく 1 行だけの CSV で試します。削除は取り消せないので、その 1 人が退職日を過ぎていること、アプリ設定の修正とタスクの引き継ぎが済んでいることを確かめてから実行してください。
関連ページ
- アプリに影響を与えない、安全なユーザ削除の仕方
- System Settings REST API で入社と異動を反映する(近日公開予定)
- SwaggerでQuestetra REST API を使ってみる
- R3175: 応答エラーリスト (ワークフロー基盤 API)


