/** * 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 を実環境の値に書き換えてください。 * 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"); 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 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の疎通・ネットワーク設定を確認してください。"); process.exit(1); } const text = await response.text(); if (!response.ok) { console.error(`[エラー] HTTP ${response.status} ${response.statusText}`); console.error(text); process.exit(1); } let json; try { json = JSON.parse(text); } catch (err) { console.error("[エラー] レスポンスがJSONとして解析できませんでした。"); console.error(text); process.exit(1); } // レスポンス構造の確認用ログ(初回はここを見て構造を把握してください) 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); console.log("\n次のステップ: latest.jsonをClaudeのチャットにアップロードして仕様書化を依頼するか、"); console.log("configs/site-{SiteId}/ 配下のファイルを直接編集・指示して修正してください。"); } main();