サイト取得
概要¶
APIを使用してサイト情報を取得することができます。
制限事項¶
wikiには対応していません。
事前準備¶
APIの操作を行う前にAPIキーの作成を実施してください。また、この機能はテナント管理者でないと行えないため、ユーザ管理からテナント管理者の設定を行ってください。
リクエスト¶
下記のリクエスト形式で、jsonデータを送信します。
| 設定項目 | 値 |
|---|---|
| HTTPメソッド | POST |
| Content-Type | application/json |
| 文字コード | UTF-8 |
| URL | http://{サーバ名}/api/items/{サイトID}/getsite(※1) |
| Body | 以下のjsonデータを参考のこと |
(※1){サーバ名}、{サイトID}の部分は、適宜、環境に合わせて編集してください。
pleasanter.netの場合は以下の形式になります。
https://pleasanter.net/fs/api/items/{サイトID}/getsite
{サイトID}には、取得対象のサイトIDを指定してください。
JSON¶
レスポンス¶
下記の形式のJSONデータが返却されます。
JSON¶
{
"StatusCode": 200,
"Response": {
"Data": {
"TenantId": 1,
"SiteId": 12345,
"UpdatedTime": "2023-08-17T12:00:00",
"Ver": 1,
"Title": "記録テーブル",
"Body": "",
"SiteName": "",
"SiteGroupName": "",
"GridGuide": "",
"EditorGuide": "",
"CalendarGuide": "",
"CrosstabGuide": "",
"GanttGuide": "",
"BurnDownGuide": "",
"TimeSeriesGuide": "",
"KambanGuide": "",
"ImageLibGuide": "",
"ReferenceType": "Results",
"ParentId": 12344,
"InheritPermission": 3301,
"Permissions": [
],
"SiteSettings": {
"Version": 1.017,
"ReferenceType": "Results",
"EditorColumnHash": {
"General": [
"ResultId",
"Ver",
"Title",
"Body",
"Status",
"Manager",
"Owner",
"Comments",
"ClassA",
"ClassB",
"ClassC"
]
},
"NoDisplayIfReadOnly": false
},
"Publish": false,
"DisableCrossSearch": false,
"LockedTime": "1899-12-30T00:00:00",
"LockedUser": 0,
"ApiCountDate": "1899-12-30T00:00:00",
"ApiCount": 0,
"Comments": "[]",
"Creator": 1,
"Updator": 1,
"CreatedTime": "2023-08-17T09:00:00",
"ApiVersion": 1.1,
"ClassHash": {
},
"NumHash": {
},
"DateHash": {
},
"DescriptionHash": {
},
"CheckHash": {
},
"AttachmentsHash": {
}
}
}
}
サンプルコード¶
Note
コード内の【 ... 】は適宜修正してください。
1. 複数のサイトのアクセス権を、1行1件のCSVに出力する
サイトID一覧(CSV)のサイトごとに、サイト取得APIでアクセス権を取得し、「どのサイトで、誰に、どの権限が付いているか」を1行1件のCSVに出力します。権限を継承しているサイトは、継承元のアクセス権を取得します。組織・グループ・ユーザーのIDは名前に変換し、権限の値はパターン名(読取専用・書き込み・リーダー・管理者・特殊)と9つの個別の権限に分けて出力します。
実務での使いどころ¶
監査への対応や、人事異動のあとの権限の棚卸に使えます。アクセス権は、サイトごとに「テーブルの管理」の「アクセス制御」を開かないと確認できず、複数のサイトをまとめて一覧にする機能はありません。継承しているサイトでは、継承元を開き直す必要もあります。出力したCSVをExcelで開けば、無効にした組織やユーザーに権限が残っていないかも確かめられます。
事前準備¶
1:棚卸したいサイトのIDを、1行目を見出しSiteIdにしたCSV(sites.csv、UTF-8)に書きます。
2:サンプルコードのBASE_URL・API_KEYを書き替えてください。APIキーは、テナント管理者のものを使います。
Python¶
# ==========================================================
# アクセス権の棚卸:サイトID一覧(CSV)のサイトごとに、サイト取得APIでアクセス権を取得し、
# 「どのサイトで、誰に、どの権限が付いているか」を1行1件のCSVに出力します。
# 権限を継承しているサイトは、継承元のアクセス権を取得します。
# ==========================================================
import csv
from pathlib import Path
import requests
# ===== 設定 =====
# APIキーは、テナント管理者のものを使ってください(サイト取得APIの前提)
BASE_URL = "【URL】"
API_KEY = "【APIキー】"
INPUT_CSV = Path("./sites.csv") # 1行目は見出し「SiteId」
OUTPUT_CSV = Path("./site_permissions.csv")
PAGE_SIZE = 200
# 権限値はビットの和。標準のパターンは値が完全に一致するときのみ、その名前にする
PERMISSION_BITS = [
(1, "読取り"), (2, "作成"), (4, "更新"), (8, "削除"), (16, "メール送信"),
(32, "エクスポート"), (64, "インポート"), (128, "サイトの管理"), (256, "権限の管理"),
]
PATTERNS = {1: "読取専用", 31: "書き込み", 255: "リーダー", 511: "管理者"}
KIND_NAMES = {"Dept": "組織", "Group": "グループ", "User": "ユーザー"}
HEADER = (["サイトID", "タイトル", "継承元サイトID", "継承元タイトル", "対象種別", "対象ID", "対象名", "権限パターン"]
+ [name for _, name in PERMISSION_BITS] + ["備考"])
def api_post(path, payload=None):
"""Pleasanter APIへPOSTする。レスポンスのJSONを返す(HTTPエラーでも本文を返す)"""
response = requests.post(
f"{BASE_URL}{path}",
json={"ApiVersion": 1.1, "ApiKey": API_KEY, **(payload or {})},
headers={"Content-Type": "application/json"},
timeout=60,
)
return response.status_code, response.json()
def fetch_all(path):
"""取得件数に応じてOffsetを進めながら、全件を取得する"""
rows = []
while True:
_, body = api_post(path, {"Offset": len(rows), "PageSize": PAGE_SIZE})
page = body["Response"]["Data"]
rows.extend(page)
if len(page) == 0 or len(rows) >= body["Response"]["TotalCount"]:
return rows
def load_names():
"""組織・グループ・ユーザーの「ID → (名前, 無効か)」を、最初に1回だけ取得する"""
return {
"Dept": {d["DeptId"]: (d["DeptName"], d.get("Disabled")) for d in fetch_all("/api/depts/get")},
"Group": {g["GroupId"]: (g["GroupName"], g.get("Disabled")) for g in fetch_all("/api/groups/get")},
"User": {u["UserId"]: (u["Name"], u.get("Disabled")) for u in fetch_all("/api/users/get")},
}
def get_site(site_id, cache):
"""サイトを取得する(同じサイトは1回のみ)。失敗したら (None, メッセージ) を返す"""
if site_id not in cache:
status, body = api_post(f"/api/items/{site_id}/getsite")
cache[site_id] = (body["Response"]["Data"], "") if status == 200 else (None, body.get("Message", f"HTTP {status}"))
return cache[site_id]
def read_site_ids(path):
"""入力のサイトIDを、重複を除いて読んだ順に返す"""
with open(path, encoding="utf-8-sig", newline="") as f:
ids = [int(row["SiteId"]) for row in csv.DictReader(f) if row["SiteId"].strip()]
return list(dict.fromkeys(ids))
def permission_cells(value):
"""権限値を、パターン名と9つの個別権限(付いていれば〇)に分解する"""
return [PATTERNS.get(value, "特殊")] + ["〇" if value & bit else "" for bit, _ in PERMISSION_BITS]
def site_rows(site_id, names, cache):
"""1サイト分の出力行を返す"""
site, error = get_site(site_id, cache)
if site is None:
return [[site_id, "", "", "", "", "", "", ""] + [""] * len(PERMISSION_BITS) + [error]]
# 継承しているサイトの Permissions は空になるため、継承元(継承の大元)のものを使う
inherit_id = int(site["InheritPermission"])
source, error = (site, "") if inherit_id == site_id else get_site(inherit_id, cache)
if source is None:
return [[site_id, site["Title"], inherit_id, "", "", "", "", ""] + [""] * len(PERMISSION_BITS) + [f"継承元を取得できません:{error}"]]
head = [site_id, site["Title"], inherit_id, source["Title"]]
permissions = source.get("Permissions") or []
if not permissions:
# 誰にも権限が付いていないサイトも、一覧で分かるように1行出す
return [head + ["", "", "", ""] + [""] * len(PERMISSION_BITS) + ["アクセス権なし"]]
rows = []
for permission in permissions:
kind, target_id, value = permission.split(",")
name, disabled = names[kind].get(int(target_id), ("", False))
rows.append(head + [KIND_NAMES.get(kind, kind), int(target_id), name]
+ permission_cells(int(value)) + ["無効" if disabled else ""])
return rows
def main():
names = load_names()
cache = {}
rows = [row for site_id in read_site_ids(INPUT_CSV) for row in site_rows(site_id, names, cache)]
# Excel でそのまま開けるように、BOM付きのUTF-8で書く
with open(OUTPUT_CSV, "w", encoding="utf-8-sig", newline="") as f:
writer = csv.writer(f)
writer.writerow(HEADER)
writer.writerows(rows)
print(f"{len(rows)} 行を {OUTPUT_CSV} に出力しました。")
if __name__ == "__main__":
main()
出力の例(site_permissions.csv)¶
サイトID,タイトル,継承元サイトID,継承元タイトル,対象種別,対象ID,対象名,権限パターン,読取り,作成,更新,削除,メール送信,エクスポート,インポート,サイトの管理,権限の管理,備考
887,案件管理,887,案件管理,組織,26,新設室,特殊,〇,,,,,〇,,,,
869,作業明細,2,プロジェクト,ユーザー,1,Administrator,管理者,〇,〇,〇,〇,〇,〇,〇,〇,〇,
注記¶
- サイト取得APIのアクセス権(
Permissions)は、「種別,ID,権限値」の文字列の配列で返ります。権限値は、読取り=1、作成=2、更新=4、削除=8、メール送信=16、エクスポート=32、インポート=64、サイトの管理=128、権限の管理=256の和です。 - 権限を継承しているサイトの
Permissionsは空で返ります。このサンプルでは、InheritPermissionのサイトのアクセス権を取得します。 - 存在しないID・削除したサイト・レコードのIDは、取得に失敗し、備考にメッセージを入れて次のサイトへ進みます。
- レコードごとのアクセス権と、グループのメンバーは出力しません。
対応バージョン¶
| 対応バージョン | 内容 |
|---|---|
| 1.3.4.0 以降 | 機能追加 |
