ken_nogi/Pleasanter/.claude/js/get-master-data.js
Kenichiro NOGI ce58cb4be4 初回コミット: dev配下(NodeSrv/Pleasanter等)をGitea管理下に統合
GitHub(nextgroup2706/ken_nogi)は今後使わず自社Gitea運用に切替え。
NodeSrvは旧リポジトリの履歴を破棄しファイルのみ統合(Dokploy用サービスアカウントは
別途mygit-admin/NodeSrv.gitに履歴あり)。notepmエクスポート(12GB)とPleasanter
インストーラzip(208MB)はサイズが大きいため.gitignoreで除外。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-04 15:37:06 +09:00

132 lines
4.6 KiB
JavaScript
Raw Permalink 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/{env}/master/ 配下に保存しますresolve-names.js が読み込む)。
* ClaudePleasanter直下に置く共通実装。全プロジェクトの薄いラッパーから require される。
* 保存先はlayoutによらず共通configs/{env}/master/)。
*
* 使い方:
* node get-master-data.js --project="..." --env=production
*
* 参照した公式マニュアル:
* - 開発者向け機能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 { resolveProjectRoot, loadServerConfig } = require("./resolve-project");
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 { baseDir, env } = resolveProjectRoot();
const { BaseUrl, ApiKey, ApiVersion } = loadServerConfig(env);
const outDir = path.join(baseDir, "configs", env, "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();