ken_nogi/ClaudePleasanter/IC(東京)【引継依頼】/.claude/js/get-master-data.js
Kenichiro NOGI ed33892f08 chore: 作業中の変更を整理しコミット(複数プロジェクト分)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 11:09:50 +09:00

143 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* get-master-data.js
* ------------------------------------------------------------
* Pleasanterのユーザー/組織(部署)/グループ一覧を取得し、
* ./configs/ 配下に保存しますresolve-names.js が読み込む)。
*
* 使い方:
* node get-master-data.js
* node get-master-data.js ./config.json ← 設定ファイルを明示指定する場合
*
* 参照した公式マニュアル:
* - 開発者向け機能APIユーザ操作ユーザ取得全て
* https://pleasanter.org/ja/manual/api-user-get-all
* - 開発者向け機能API組織操作組織取得
* https://pleasanter.org/ja/manual/api-dept-get
* - 開発者向け機能APIグループ操作グループ取得
* https://pleasanter.org/ja/manual/api-group-get
* ------------------------------------------------------------
*/
const fs = require("fs");
const path = require("path");
const TARGETS = [
{ key: "users", endpoint: "users/get", outFile: "master_users.json", label: "ユーザー", idField: "UserId" },
{ key: "depts", endpoint: "depts/get", outFile: "master_depts.json", label: "組織", idField: "DeptId" },
{ key: "groups", endpoint: "groups/get", outFile: "master_groups.json", label: "グループ", idField: "GroupId" },
];
// 一部API/api/users/get 等はページング応答TotalCount > 1回あたりのData件数を返すため、
// 全件取得できるまで Offset をずらして繰り返し取得し、Data配列を結合する。
async function fetchAndSave(target, { BaseUrl, ApiKey, ApiVersion }, outDir) {
const url = `${BaseUrl.replace(/\/+$/, "")}/api/${target.endpoint}`;
let allData = [];
let offset = 0;
let totalCount = null;
let firstJson = null;
while (true) {
const body = {
ApiVersion: ApiVersion || "1.1",
ApiKey: ApiKey,
Offset: offset,
};
console.log(`[INFO] 取得先: ${url} (Offset: ${offset})`);
let response;
try {
response = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
} catch (err) {
console.error(`[エラー] ${target.label}の取得に失敗しました:`, err.message);
return false;
}
const text = await response.text();
if (!response.ok) {
console.error(`[エラー] HTTP ${response.status} ${response.statusText}`);
console.error(text);
return false;
}
let json;
try {
json = JSON.parse(text);
} catch (err) {
console.error(`[エラー] ${target.label}のレスポンスがJSONとして解析できませんでした。`);
console.error(text);
return false;
}
if (!firstJson) firstJson = json;
const pageData = json?.Response?.Data || [];
allData = allData.concat(pageData);
totalCount = json?.Response?.TotalCount ?? allData.length;
if (pageData.length === 0 || allData.length >= totalCount) break;
offset = allData.length;
}
// ページ間でOffset起点がずれて重複が混ざる場合があるため、idFieldで重複排除する
const seen = new Set();
allData = allData.filter((item) => {
const id = item[target.idField];
if (seen.has(id)) return false;
seen.add(id);
return true;
});
// 結合済みのData配列で1件目のレスポンスを上書きし、全件入りのJSONとして保存する
const outJson = { ...firstJson, Response: { ...firstJson.Response, Data: allData } };
const outFile = path.join(outDir, target.outFile);
fs.writeFileSync(outFile, JSON.stringify(outJson, null, 2), "utf-8");
console.log(`[OK] ${target.label}: ${allData.length}/${totalCount}件 保存しました: ${outFile}`);
return true;
}
async function main() {
const configPath = process.argv[2] || path.join(path.join(__dirname, "..", ".."), "config.json");
if (!fs.existsSync(configPath)) {
console.error(`[エラー] 設定ファイルが見つかりません: ${configPath}`);
console.error("config.example.json をコピーして config.json を作成してください。");
process.exit(1);
}
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
const { BaseUrl, ApiKey, ApiVersion } = config;
if (!BaseUrl || !ApiKey) {
console.error("[エラー] config.json に BaseUrl / ApiKey を設定してください。");
process.exit(1);
}
const outDir = path.join(path.join(__dirname, "..", ".."), "configs", "master");
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
const results = [];
for (const target of TARGETS) {
const ok = await fetchAndSave(target, { BaseUrl, ApiKey, ApiVersion }, outDir);
results.push({ target: target.label, ok });
}
console.log("\n==== 取得結果まとめ ====");
for (const { target, ok } of results) {
console.log(` ${target}: ${ok ? "OK" : "失敗"}`);
}
if (results.some((r) => !r.ok)) {
process.exit(1);
}
}
main();