Pleasanterのサイト情報を一括更新する

本記事は、[OSSのノーコード・ローコード開発ツール「プリザンター」 Advent Calendar 2022](https://qiita.com/advent-calendar/2022/pleasanter) の10日目の記事です。

# 前置き
[こちら](https://qiita.com/m-isik/items/3f558fd8e0e0298dee3e)の記事で、サイト情報を再帰的に取得する方法を投稿しています。今回はこの仕組みを応用して、フォルダ配下のサイト設定を一括更新する仕組みを作ります。

# 作成するサイト
サイト設定の更新といっても、設定内容は山ほどあるので、今回は一覧画面・編集画面のガイドを一括更新する仕組みを作ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922382/0292d768-f98d-e086-5d13-fbccbf8464f5.png)
サイトID欄に一括更新したいサイト（フォルダ）のIDを指定、説明欄・一覧ガイド／編集ガイドに更新したいガイド文言を入力します。

「サイトガイド更新」ボタンクリックで、フォルダ配下の全サイトのガイドを更新します。

# 仕組み
基本前回の再帰処理とほぼ同じ。

1. サイトIDに紐づく子サイトを[拡張SQL](https://pleasanter.org/manual/extended-sql-api)で取得
1. 取得結果をループし、サイトAPIをGetSite→UpdateSiteで順次更新
1. ループの中でさらにサイトIDに紐づく子サイトを[拡張SQL](https://pleasanter.org/manual/extended-sql-api)で取得→2へ（以下再帰）

# テーブル設定
この辺も前回と同様。Onclickに処理のトリガーとなる関数**SiteGuide**を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922382/7292d927-f950-7793-54ac-374526fc6848.png)

# 実装
### 拡張SQL
SiteGuide.json.sql
前回と同じ、使いまわしです。
```sql
SELECT [SiteId],[Title],[ReferenceType]
FROM [Sites]
WHERE [ParentId]=@ParentId
```

SiteGuide.json
```json
{
    "Name": "SiteGuide",
    "Api": true
}
```
拡張SQLのセットになるJSON

### スクリプト
こちらも処理の大枠は前回と同じ。前回はサイト情報を取得→画面表示していたところを、APIで[GetSite](https://pleasanter.org/manual/script-api-get-site)→[UpdateSite](https://pleasanter.org/manual/script-api-update-site)としてサイト設定を更新します。

```javascript

//プロセスから呼ばれるメイン関数
const SiteGuide = async () => {
    //説明欄に入力されたサイトガイドを取得
    let gridGuide = $p.getControl('DescriptionA').val();
    let editorGuide = $p.getControl('DescriptionB').val();
    let siteId = $p.getControl('NumA').val();
    //最初に最上位のサイト情報を更新
    UpdateGuide(siteId, gridGuide, editorGuide);
    //拡張SQLにより子サイトを取得
    let res = await GetSites(siteId);    
    if(res.Response.Data.Table.length > 0){
        //再帰処理へ
        await SetSiteSettings(res.Response.Data.Table, gridGuide, editorGuide);
        document.getElementById('UpdateCommand').click();
    }    
};

//再帰呼び出しされる関数
const SetSiteSettings = async (table, gridGuide, editorGuide) => {
    //子サイトリストをループ
    for (let data of table) {
        //子サイトのサイトをアップデート
        UpdateGuide(data.SiteId, gridGuide, editorGuide);
        //さらに孫サイトを取得
        let res = await GetSites(data.SiteId);
        if(res.Response.Data.Table.length > 0){
            //再帰呼び出し
            await SetSiteSettings(res.Response.Data.Table, gridGuide, editorGuide);
        }
    }
};

//拡張SQLによる子サイト取得処理（前回と同じ）
const GetSites = async (siteId) => {
    let id = siteId;
    let data = {
        "ApiVersion": 1.1,        
        "Name": "SiteMap",
         "Params": {
            "RefID": id
        }
    }
    let uri = new URL(window.location.href);
    let url = `${uri.origin}/api/extended/sql`;
    let response = await fetch(url, {
        method: 'POST',
        body: JSON.stringify(data),
        headers: {
            'Content-Type': 'application/json'            
            },
    });
    return response.json();
};

//サイトAPIでサイト設定を更新
const UpdateGuide = async (siteId, gridGuide, editorGuide) => {
    //サイト設定取得
    $p.apiGetSite({
        id: siteId,
        done: function (data) {
            delete data.Response.Data.Comments;
            //ReferenceTypeにより更新するガイドの種類を切り分け
            //※ReferenceType=Site(フォルダ)は詳細画面無し
            //※ReferenceType=Wikiは一覧画面無し
            switch(data.Response.Data.ReferenceType){
                case 'Sites':
                    data.Response.Data.GridGuide = gridGuide;
                    break;
                case 'Issues':
                case 'Results':
                    data.Response.Data.GridGuide = gridGuide;
                    data.Response.Data.EditorGuide = editorGuide;
                    break;
                case 'Wikis':
                    data.Response.Data.EditorGuide = editorGuide;
                    break;
            }
            //サイト設定更新
            $p.apiUpdateSite({
                id: siteId,
                data: data.Response.Data
            });
        }
    });
}

```

# 注意点
サイト数が多ければ多いなりに、システムへの性能負荷が高まるのも前回と同様。今回の方がAPIによる更新もあるので、より注意が必要です。