167 lines
6.1 KiB
JavaScript
167 lines
6.1 KiB
JavaScript
/**
|
||
* get-site-config.js
|
||
* ------------------------------------------------------------
|
||
* プリザンターの指定サイトの構成情報(SiteSettings等)を取得し、
|
||
* ./configs/ 配下にタイムスタンプ付きJSONとして保存します。
|
||
*
|
||
* 使い方:
|
||
* node get-site-config.js
|
||
* node get-site-config.js ./config.json ← 設定ファイルを明示指定する場合
|
||
*
|
||
* 事前準備:
|
||
* 1. config.example.json を config.json にコピーし、
|
||
* BaseUrl / SiteId / ApiKey を実環境の値に書き換えてください。
|
||
* SiteId はカンマ区切りで複数指定可能です(例: "480111,438166,96235")。
|
||
* 1件のみの場合は従来通り数値(例: 480111)でも構いません。
|
||
* 2. Node.js 18以降(組み込みfetchを使用)
|
||
*
|
||
* 参照した公式マニュアル:
|
||
* - 開発者向け機能:API:サイト操作:サイト更新
|
||
* https://pleasanter.org/manual/api-site-update
|
||
* - 開発者向け機能:API:サイト操作:サイト設定の更新(部分追加/更新/削除)
|
||
* https://pleasanter.org/ja/manual/api-update-sitesettings
|
||
*
|
||
* 注意:
|
||
* プリザンターのバージョンにより get のレスポンス構造
|
||
* (SiteSettingsが Response.Site 配下にあるか等)が異なる場合があります。
|
||
* 初回実行時はコンソールに出力されるレスポンスのトップレベルキーを確認し、
|
||
* 想定通りの構造か確認してください。
|
||
* ------------------------------------------------------------
|
||
*/
|
||
|
||
const fs = require("fs");
|
||
const path = require("path");
|
||
const { extractSiteConfig } = require("./extract-site-config");
|
||
|
||
// config.json の SiteId(数値 / カンマ区切り文字列 / 配列)を
|
||
// 個々のSiteId文字列の配列に正規化する。
|
||
function parseSiteIds(rawSiteId) {
|
||
const list = Array.isArray(rawSiteId) ? rawSiteId : String(rawSiteId).split(",");
|
||
return list
|
||
.map((id) => String(id).trim())
|
||
.filter((id) => id.length > 0);
|
||
}
|
||
|
||
// 1サイト分の取得・保存・抽出処理
|
||
async function fetchAndSaveSite(siteId, { BaseUrl, ApiKey, ApiVersion }) {
|
||
const url = `${BaseUrl.replace(/\/+$/, "")}/api/items/${siteId}/getsite`;
|
||
const body = {
|
||
ApiVersion: ApiVersion || "1.1",
|
||
ApiKey: ApiKey,
|
||
};
|
||
|
||
console.log(`[INFO] 取得先: ${url}`);
|
||
console.log(`[INFO] SiteId: ${siteId}`);
|
||
|
||
let response;
|
||
try {
|
||
response = await fetch(url, {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify(body),
|
||
});
|
||
} catch (err) {
|
||
console.error("[エラー] リクエスト送信に失敗しました:", err.message);
|
||
console.error("BaseUrlの疎通・ネットワーク設定を確認してください。");
|
||
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("[エラー] レスポンスがJSONとして解析できませんでした。");
|
||
console.error(text);
|
||
return false;
|
||
}
|
||
|
||
// レスポンス構造の確認用ログ(初回はここを見て構造を把握してください)
|
||
console.log("[INFO] レスポンス トップレベルキー:", Object.keys(json));
|
||
if (json.Response) {
|
||
console.log("[INFO] Response配下のキー:", Object.keys(json.Response));
|
||
}
|
||
|
||
// 保存
|
||
const outDir = path.join(__dirname, "configs");
|
||
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
|
||
|
||
const timestamp = new Date()
|
||
.toISOString()
|
||
.replace(/[:.]/g, "-");
|
||
const outFile = path.join(outDir, `site-${siteId}_${timestamp}.json`);
|
||
|
||
fs.writeFileSync(outFile, JSON.stringify(json, null, 2), "utf-8");
|
||
|
||
// 常に「最新」ファイルも別名で保持(Claudeへのアップロード用に固定名があると便利)
|
||
const latestFile = path.join(outDir, `site-${siteId}_latest.json`);
|
||
fs.writeFileSync(latestFile, JSON.stringify(json, null, 2), "utf-8");
|
||
|
||
console.log(`[OK] 保存しました: ${outFile}`);
|
||
console.log(`[OK] 最新版としても保存しました: ${latestFile}`);
|
||
|
||
// 取得と同時に Scripts/Styles/ServerScripts/Processes/ガイドHTML も抽出する
|
||
console.log("\n[INFO] 続けて設定の個別ファイル抽出を実行します...");
|
||
extractSiteConfig(latestFile);
|
||
|
||
return true;
|
||
}
|
||
|
||
async function main() {
|
||
const configPath = process.argv[2] || 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, SiteId, ApiKey, ApiVersion } = config;
|
||
|
||
if (!BaseUrl || !SiteId || !ApiKey) {
|
||
console.error("[エラー] config.json に BaseUrl / SiteId / ApiKey を設定してください。");
|
||
process.exit(1);
|
||
}
|
||
|
||
const siteIds = parseSiteIds(SiteId);
|
||
if (siteIds.length === 0) {
|
||
console.error("[エラー] config.json の SiteId から有効なサイトIDを取得できませんでした。");
|
||
process.exit(1);
|
||
}
|
||
|
||
const multiple = siteIds.length > 1;
|
||
const results = [];
|
||
|
||
for (const [index, siteId] of siteIds.entries()) {
|
||
if (multiple) {
|
||
console.log(`\n==== [${index + 1}/${siteIds.length}] SiteId: ${siteId} ====`);
|
||
}
|
||
const ok = await fetchAndSaveSite(siteId, { BaseUrl, ApiKey, ApiVersion });
|
||
results.push({ siteId, ok });
|
||
}
|
||
|
||
if (multiple) {
|
||
console.log("\n==== 取得結果まとめ ====");
|
||
for (const { siteId, ok } of results) {
|
||
console.log(` SiteId ${siteId}: ${ok ? "OK" : "失敗"}`);
|
||
}
|
||
}
|
||
|
||
console.log("\n次のステップ: latest.jsonをClaudeのチャットにアップロードして仕様書化を依頼するか、");
|
||
console.log("configs/site-{SiteId}/ 配下のファイルを直接編集・指示して修正してください。");
|
||
|
||
if (results.some((r) => !r.ok)) {
|
||
process.exit(1);
|
||
}
|
||
}
|
||
|
||
main();
|