インポート
概要¶
APIを使用してユーザ情報をインポートします。
事前準備¶
APIの操作を行う前にAPIキーの作成を実施してください。
リクエスト¶
下記のリクエスト形式で、CSVデータとJSONパラメータを送信します。
| 設定項目 | 値 |
|---|---|
| HTTPメソッド | POST |
| Content-Type | multipart/form-data |
| 文字コード | UTF-8 |
| URL | http://{サーバー名}/api/users/import (※1) |
| Body | 下記「Bodyに指定する項目」を参照のこと |
(※1){サーバー名}の部分は、適宜、環境に合わせて編集してください。
Bodyに指定する項目¶
| 項目名 | 値 |
|---|---|
| parameters | 下記「APIパラメータ」の内容をJSON形式の文字列で指定 |
| file | 登録するCSVファイルのバイナリデータ |
APIパラメータ¶
| 項目名 | 設定例 | 備考 |
|---|---|---|
| ApiVersion | 1.1 | APIバージョン |
| ApiKey | 3da0fa3a7R61faf821... | 取得したAPIキー |
| Encoding | Shift-JIS | CSVファイルのエンコーディング。"UTF-8"または"Shift-JIS"を指定 |
実行例のサンプル¶
PowerShell(version6.0 以降)のサンプル¶
PowerShell¶
$uri = 'http://servername/api/users/import'
$filePath = "./sample.csv"
$form = @{
parameters = ConvertTo-Json @{
ApiVersion = 1.1;
ApiKey = "4d84b4773a58bbc3c4...";
Encoding = "UTF-8";
};
file = Get-Item -Path $filePath;
}
Invoke-WebRequest -Uri $uri -Method Post -Form $form
Pythonのサンプル¶
Python¶
import requests
import json
url = "https://servername/api/users/import"
filePath = "./sample.csv"
data = {
"parameters": json.dumps({
"ApiVersion" : 1.1,
"ApiKey" : "4d84b4773a58bbc3c4...",
"Encoding" : "UTF-8"
})
}
files = {
"file":("sample.csv", open(filePath,"rb"), "text/csv")
}
response = requests.post(url, data, files=files)
print(response.content.decode())
レスポンス¶
下記の形式のjsonデータが返却されます。
JSON¶
サンプルコード¶
Note
コード内の【 ... 】は適宜修正してください。
1. 人事CSVを正としてユーザーを同期し、退職者は削除せず無効化する
人事システムが出力したユーザーCSV(ログインID・氏名・社員番号・メールアドレス・組織コード)を読み込み、ユーザーのインポートAPIでまとめて作成・更新します。プリザンターにいてCSVから消えたユーザー(退職者)は、削除せず無効化します。 無効だったユーザーがCSVに戻ってきた場合(再入社など)は、有効に戻ります。
実務での使いどころ¶
入社・退職・異動・改姓は毎月のように発生します。人事システムとプリザンターのユーザーがずれると、退職者がログインできたまま残ったり、異動した人の所属組織が古いままになったりします。人事CSVを正として定期的に実行すれば、追加・更新・退職者の無効化を、人が突き合わせることなく反映できます。
退職者を削除せず無効化するのは、過去レコードの作成者・担当者の表示を保つためです。組織も同じ考え方で同期する場合は、「組織更新」のサンプルを先に実行してください。
事前準備¶
1:テナント管理者権限のAPIキーを用意してください。
2:人事システム側から、以下の形式のCSVファイル(UTF-8)を出力してください。毎回、全ユーザーをフルで出力する形式である必要があります(差分のみの形式では、CSVに無い=退職と判定できません)。
| 列名 | 内容 |
|---|---|
| login_id | ログインID。プリザンターのログインIDと突合するキー |
| user_name | 氏名 |
| user_code | ユーザコード(社員番号など) |
| メールアドレス(任意) | |
| dept_code | 所属組織の組織コード(任意) |
3:下記サンプルコードのKEEP_LOGIN_IDSに、CSVに含まれなくても無効化しないユーザー(管理者、このスクリプトのAPIキーのユーザー、システム連携用など)のログインIDを入れてください。既定値はAdministratorです。
4:最初はDRY_RUN = Trueで実行し、無効化の対象に意図しないユーザーが含まれていないことを確かめてからFalseにしてください。
Python¶
import csv
import json
from pathlib import Path
import requests
# ==============================
# Pleasanter 接続設定
# ==============================
BASE_URL = "【URL】"
API_KEY = "【APIキー】"
API_VERSION = 1.1
# ==============================
# ファイル設定(環境にあわせ適宜変更してください)
# ==============================
INPUT_DIR = Path("./input")
USERS_CSV = INPUT_DIR / "users.csv"
OUTPUT_DIR = Path("./output")
IMPORT_CSV = OUTPUT_DIR / "users_import.csv"
# CSVに無くても無効化しないユーザーのログインID
# (管理者、このスクリプトのAPIキーのユーザー、システム連携用など。環境にあわせて足してください)
KEEP_LOGIN_IDS = {"Administrator"}
# True の場合、実際の更新は行わず対象だけを出力する
DRY_RUN = False
# ユーザーインポートのCSVの見出し
IMPORT_HEADERS = ["ログインID", "名前", "ユーザコード", "メールアドレス", "組織コード", "無効"]
# ==============================
# CSV入出力
# ==============================
def read_csv(path):
with open(path, "r", encoding="utf-8-sig", newline="") as f:
return [
{k.strip(): (v or "").strip() for k, v in row.items()}
for row in csv.DictReader(f)
]
def write_import_csv(path, rows):
path.parent.mkdir(parents=True, exist_ok=True)
with open(path, "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerow(IMPORT_HEADERS)
for row in rows:
writer.writerow(
[
row["login_id"],
row["user_name"],
row["user_code"],
row["mail"],
row["dept_code"],
"0", # CSVにいる人は有効にする(再入社した人も有効に戻る)
]
)
# ==============================
# Pleasanter API操作
# ==============================
def post_json(url, payload):
r = requests.post(
url,
json=payload,
headers={"Content-Type": "application/json"},
timeout=60,
)
r.raise_for_status()
return r.json()
def get_all(path):
# 1回で取れる件数(既定200件)を超えても全件を取得する
rows, offset = [], 0
while True:
data = post_json(
f"{BASE_URL}/api/{path}/get",
{"ApiVersion": API_VERSION, "ApiKey": API_KEY, "Offset": offset},
)
response = data.get("Response", {})
page = response.get("Data", [])
rows.extend(page)
offset += len(page)
if not page or offset >= response.get("TotalCount", 0):
return rows
def get_users():
return {row["LoginId"]: row for row in get_all("users") if row.get("LoginId")}
def get_dept_codes():
return {row["DeptCode"] for row in get_all("depts") if row.get("DeptCode")}
def import_users(path):
# CSVにいる人をまとめて作成・更新する
with open(path, "rb") as f:
r = requests.post(
f"{BASE_URL}/api/users/import",
data={
"parameters": json.dumps(
{"ApiVersion": API_VERSION, "ApiKey": API_KEY, "Encoding": "UTF-8"}
)
},
files={"file": (path.name, f, "text/csv")},
timeout=300,
)
r.raise_for_status()
return r.json()
def disable_user(user_id):
# Disabled だけを送る(メールアドレス・所属組織などはそのまま残る)
return post_json(
f"{BASE_URL}/api/users/{user_id}/update",
{"ApiVersion": API_VERSION, "ApiKey": API_KEY, "Disabled": True},
)
# ==============================
# メイン処理
# ==============================
def main():
user_rows = read_csv(USERS_CSV)
csv_login_ids = {row["login_id"] for row in user_rows}
# プリザンターに無い組織コードがあれば、1件も変えずに止める
# (そのまま取り込むと、エラーにならずに所属組織が空になる)
dept_codes = get_dept_codes()
unknown = sorted(
{row["dept_code"] for row in user_rows if row["dept_code"]} - dept_codes
)
if unknown:
raise SystemExit(
f"プリザンターに無い組織コードがあるため中止しました: {', '.join(unknown)}"
)
existing_users = get_users()
new_login_ids = sorted(csv_login_ids - existing_users.keys())
# CSVから消えた人(既に無効な人・無効化しない人は除く)
to_disable = [
user
for login_id, user in sorted(existing_users.items())
if login_id not in csv_login_ids
and login_id not in KEEP_LOGIN_IDS
and not user.get("Disabled")
]
write_import_csv(IMPORT_CSV, user_rows)
print(f"インポート用CSV: {IMPORT_CSV}({len(user_rows)}件、うち新規 {len(new_login_ids)}件)")
for user in to_disable:
print(f"無効化の対象: {user['LoginId']} {user.get('Name', '')}")
if DRY_RUN:
print("DRY_RUN=True のため、インポートと無効化は実行しません")
return
result = import_users(IMPORT_CSV)
print(f"インポート: {result.get('Message')}")
for user in to_disable:
disable_user(user["UserId"])
print(f"無効化: {len(to_disable)}件")
if __name__ == "__main__":
main()
- CSVの組織コードにプリザンターに無いものがあると、何も変えずに止まります。そのまま取り込むと、エラーにならずに所属組織が空になるためです。
- 無効化は、ユーザーの更新APIで
Disabledのみを送ります。インポートで無効にすると、メールアドレスの列を空で送ることになり、既存のメールアドレスが消えるためです。 - パスワードはこのサンプルでは設定しません。新しく作られたユーザーの初回ログインの方法(パスワードの初期設定、SSO・LDAPなど)は、運用に合わせて用意してください。
エラー時の確認事項¶
・API使用時の注意点やエラーが発生する場合の確認事項
・FAQ:変更後の設定ファイルやAPIリクエスト(JSON形式)が正しく認識されない場合の確認事項
