サイトコピー
概要¶
APIを使用してサイト設定を更新することができます。
制限事項¶
- 期限付きテーブルおよび、記録テーブルのみ使用可能です。
事前準備¶
APIの操作を行う前にAPIキーの作成を実施してください。また、この機能はテナント管理者でないと行えないため、ユーザ管理からテナント管理者の設定を行ってください。
リクエスト¶
下記のリクエスト形式で、jsonデータを送信します。
| 設定項目 | 値 |
|---|---|
| HTTPメソッド | POST |
| Content-Type | application/json |
| 文字コード | UTF-8 |
| URL | http://{サーバ名}/api/items/{サイトID}/copysitepackage(※1) |
| Body | 以下のjsonデータを参考のこと |
(※1){サーバ名}、{サイトID}の部分は、適宜、環境に合わせて編集してください。
pleasanter.netの場合は以下の形式になります。
https://pleasanter.net/fs/api/items/{サイトID}/copysitepackage
{サイトID}には、コピーするサイトのうちタイトル更新対象のサイトIDを指定してください。
JSON¶
{
"ApiVersion": "1.1",
"ApiKey": "345yuAjA6789dA09d8uj6...",
"TargetSiteId": 466220,
"SiteTitle": "test",
"SelectedSites": [
{
"SiteId": 466217
},
{
"SiteId": 466218,
"IncludeData": false
}
],
"IncludeSitePermission": false,
"IncludeRecordPermission": true,
"IncludeColumnPermission": false,
"IncludeNotifications": true,
"IncludeReminders": true
}
| カラム | 設定内容 |
|---|---|
| TargetSiteId | Copy先のフォルダのサイトIDを指定します。省略する場合、トップ画面にコピーします。 |
| SiteTitle | URLの{サイトID}に記載したサイトのタイトルを指定します。サイトのタイトルを変更する場合に使用してください。 |
| SelectedSites | コピーするサイトを指定します。記載方法は、サイトパッケージをエクスポートした際の"Convertors"パラメータと同等の値を設定してください。 |
※IncludeSitePermission以降のパラメータについては、サイトパッケージをエクスポートした際の、"HeaderInfo"パラメータと同等の値を設定してください。
レスポンス¶
下記の形式のjsonデータが返却されます。
JSON¶
{
"StatusCode": 200,
"Response": {
"Data": "[
{\"OldSiteId\":466217,\"NewSiteId\":466221,\"ReferenceType\":\"Sites\",\"Title\":\"test\"},
{\"OldSiteId\":466218,\"NewSiteId\":466222,\"ReferenceType\":\"Results\",\"Title\":\"記録テーブル\"}
]"
}
}
サンプルコード¶
Note
コード内の【 ... 】は適宜修正してください。
1. 案件一覧(CSV)から、案件ごとのフォルダをテンプレートから作る
案件一覧(CSV)の1行ごとに、テンプレートのフォルダをサイトコピーAPIで複製し、フォルダ名を「案件コード 案件名」にします。フォルダの中の「作業区分」はレコードごと、「作業明細」は空で複製します。複製したフォルダとサイトのIDは、結果のCSVに出力します。
実務での使いどころ¶
案件・プロジェクト・顧客ごとに、同じ構成のテーブル一式を用意する運用に使えます。画面のサイトコピーでは、案件ごとにコピーの操作と名前の変更を繰り返し、権限や通知を含めるかをその都度選ぶ必要があります。このサンプルでは、CSVに案件を並べて実行すれば、含める設定をそろえたまま、まとめて作れます。テンプレートの中のリンク(作業明細の「作業区分」)は、同じフォルダに複製された作業区分を指すように付け替わります。
事前準備¶
1:テンプレートとして、フォルダを1つ作り、その中に以下のテーブルを作成してください。
| テーブル | 種類 | 内容 |
|---|---|---|
| 作業区分 | 記録テーブル | 「設計」「テスト」などの区分をレコードとして登録しておく。レコードごと複製する |
| 作業明細 | 期限付きテーブル | 分類A(ClassA)を作業区分へのリンクにする。空で複製する |
2:複製先のフォルダを作成してください。案件ごとのフォルダは、この中に作られます。
3:案件を、1行目を見出し案件コード,案件名にしたCSV(projects.csv、UTF-8)に書きます。
4:サンプルコードの【 】を書き替えてください。APIキーは、テナント管理者のものを使います。まずDRY_RUN = Trueで、作るフォルダの名前を確かめてから実行すると安全です。
Python¶
# ==========================================================
# 案件ごとのサイト作成:案件一覧(CSV)の1行ごとに、テンプレートのフォルダをサイトコピーAPIで
# 複製し、フォルダ名を「案件コード 案件名」にします。作業区分のようなマスタはレコードごと、
# 作業明細は空で複製します。複製したフォルダとサイトのIDは、結果のCSVに出力します。
# ==========================================================
import csv
import json
from pathlib import Path
import requests
# ===== 設定 =====
# APIキーは、テナント管理者のものを使ってください(サイトコピーAPIの前提)
BASE_URL = "【URL】"
API_KEY = "【APIキー】"
TEMPLATE_FOLDER_ID = "【テンプレートのフォルダのサイトID】"
# テンプレートのフォルダの中で、複製するサイト。IncludeData が True のサイトはレコードも複製する
TEMPLATE_SITES = [
{"SiteId": "【作業区分のサイトID】", "IncludeData": True},
{"SiteId": "【作業明細のサイトID】", "IncludeData": False},
]
TARGET_FOLDER_ID = "【複製先のフォルダのサイトID】"
INPUT_CSV = Path("./projects.csv") # 1行目は見出し「案件コード,案件名」
OUTPUT_CSV = Path("./project_sites.csv")
# True のときは複製せず、作るフォルダの名前だけを表示する
DRY_RUN = False
# 権限・通知・リマインダーを複製に含めるか。全案件で同じ設定にする
COPY_OPTIONS = {
"IncludeSitePermission": False,
"IncludeRecordPermission": False,
"IncludeColumnPermission": False,
"IncludeNotifications": True,
"IncludeReminders": True,
}
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 check_templates():
"""複製するサイトが、テンプレートのフォルダの中の期限付き・記録テーブルかを確かめ、タイトルを返す。
存在しないサイトIDを指定すると、エラーにならず空のフォルダが作られるため、複製の前に確かめる"""
titles = []
for site in TEMPLATE_SITES:
status, body = api_post(f"/api/items/{int(site['SiteId'])}/getsite")
if status != 200:
raise SystemExit(f"サイトID {site['SiteId']} を取得できません: {body.get('Message')}")
data = body["Response"]["Data"]
if data["ParentId"] != int(TEMPLATE_FOLDER_ID) or data["ReferenceType"] not in ("Issues", "Results"):
raise SystemExit(f"サイトID {site['SiteId']} は、テンプレートのフォルダの中の期限付き・記録テーブルではありません")
titles.append(data["Title"])
return titles
def copy_project(folder_title):
"""テンプレートのフォルダを複製し、フォルダ名を folder_title にする。複製元→複製先のIDの対応を返す"""
status, body = api_post(f"/api/items/{int(TEMPLATE_FOLDER_ID)}/copysitepackage", {
"TargetSiteId": int(TARGET_FOLDER_ID),
# SiteTitle は、URLに指定したサイト(テンプレートのフォルダ)の複製先のタイトルになる
"SiteTitle": folder_title,
"SelectedSites": [{"SiteId": int(TEMPLATE_FOLDER_ID)}]
+ [{"SiteId": int(site["SiteId"]), "IncludeData": site["IncludeData"]} for site in TEMPLATE_SITES],
**COPY_OPTIONS,
})
# 指定の誤りで複製できなかったときも HTTP 200 で返り、Data に画面向けのメッセージが入る
rows = json.loads(body["Response"]["Data"]) if status == 200 else []
if not rows or any("NewSiteId" not in row for row in rows):
raise RuntimeError(f"「{folder_title}」を複製できませんでした: {body}")
return {row["OldSiteId"]: row["NewSiteId"] for row in rows}
def read_projects(path):
with open(path, encoding="utf-8-sig", newline="") as f:
return [(row["案件コード"].strip(), row["案件名"].strip()) for row in csv.DictReader(f) if row["案件コード"].strip()]
def main():
projects = read_projects(INPUT_CSV)
if DRY_RUN:
for code, name in projects:
print(f"[DRY_RUN] 作るフォルダ: {code} {name}")
return
titles = check_templates()
with open(OUTPUT_CSV, "w", encoding="utf-8-sig", newline="") as f:
writer = csv.writer(f)
writer.writerow(["案件コード", "案件名", "フォルダのサイトID"] + [f"{title}のサイトID" for title in titles])
for code, name in projects:
# 失敗したら、そこで止める(それまでに複製した案件は結果のCSVに残る)
new_ids = copy_project(f"{code} {name}")
writer.writerow([code, name, new_ids[int(TEMPLATE_FOLDER_ID)]]
+ [new_ids[int(site["SiteId"])] for site in TEMPLATE_SITES])
f.flush()
print(f"複製しました: {code} {name}(フォルダ {new_ids[int(TEMPLATE_FOLDER_ID)]})")
if __name__ == "__main__":
main()
出力の例(project_sites.csv)¶
案件コード,案件名,フォルダのサイトID,作業区分のサイトID,作業明細のサイトID
PRJ-001,A社システム更改,4927,4928,4929
PRJ-002,B社保守,4930,4931,4932
注記¶
SelectedSitesにテンプレートのフォルダも含め、URLのサイトIDにテンプレートのフォルダを指定すると、SiteTitleが複製先のフォルダのタイトルに使われます。フォルダの中のサイトは、複製先のフォルダの中に入ります。SelectedSitesは、{"SiteId": サイトID, "IncludeData": true}のようなオブジェクトの配列で指定します。サイトIDの数値の配列で指定すると複製されませんが、HTTPステータスは200のまま、Dataに「ファイルの読込に失敗しました。」のメッセージが入ります。このサンプルでは、Dataに複製先のサイトID(NewSiteId)が無ければ失敗として止めます。SelectedSitesに存在しないサイトIDを入れると、エラーにならず、タイトルの無いフォルダが作られます。このサンプルでは、複製の前にサイト取得APIで、テンプレートのフォルダの中の期限付きテーブル・記録テーブルであることを確かめます。- 同じCSVで2回実行すると、同じ名前のフォルダがもう1つ作られます。実行し終えた案件は、CSVから消してください。
- 権限・通知・リマインダーを複製に含めるかは、
COPY_OPTIONSで決めます。全案件に同じ設定を使います。
対応バージョン¶
| 対応バージョン | 内容 |
|---|---|
| 1.2.2.8 以降 | 機能追加 |
