Pleasanterで掲示板の既読管理をしてみた

## はじめに
プリザンターはあらゆる業務アプリを基本機能だけでも作成することができます。
しかし、使っていくとだんだん「こういう機能が欲しいな～」、「こういう制御をしたいな」といったやりたいことが広がっていきます。
今回はそんな「こういうことがしたいな」を満たす一助として「既読管理」ができるアプリを作成したいと思います。

## アプリの構成について
あなたはテーブルの管理権限を持っている管理者です。
今回はユーザに見てもらう「掲示板」テーブルと、掲示板を管理する為の「掲示板管理」テーブルの2つのテーブルを用意します。

### 掲示板
タイトルと内容、日付、起票者か分かる一般的な掲示板テーブルです。
全社向けの連絡やお知らせなどを記載する運用を想定しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551590/e8921637-16e9-8443-76d6-b563c7832819.png)


### 掲示板管理
上記掲示板に新しいレコードが作成、もしくは掲示板が更新された場合、管理テーブルに情報を転記します。
新規の場合は作成、更新があった場合は更新を行います。
誰かが掲示板のレコードにアクセスすると、管理テーブルに既読がつきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551590/6fd40e28-d101-835d-9ec1-16dd57925bf8.png)


## 作成手順
では実際に作成していきましょう。
今回はサーバスクリプトを使用します。
以下の処理をサーバスクリプトを使用して作成していきます。
- 「掲示板」にレコード作成時、情報を「掲示板管理」に転記する
- 「掲示板」にアクセスしたユーザがまだ既読のついていないユーザだった場合、「掲示板管理」で記録する
順番に解説していきます。

### 「掲示板」にレコード作成/更新時、情報を「掲示板管理」に転記する
items.Upsertを使用し、作成時もしくは更新時にレコードの情報を転記します。
管理テーブルのClassAには転記元のレコードIDが転記されるので、ClassAをキー項目に設定しています。
条件は「作成後」、「更新後」を指定します。
```Javascript
let data = {
    Keys: ["ClassA"],
    Title: model.Title,
    Owner:model.Owner,
    ClassHash: {
        ClassA: model.ResultId,
        ClassB: "[\"" + model.Owner + "\"]"
    },
    DateHash: {
        DateA:model.DateA
    }
};
context.Log(JSON.stringify(data));
items.Upsert(511, JSON.stringify(data));//511の個所は対象のSiteIdを入力
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551590/0ee0d8be-0f90-df3d-a748-59abc23a9b57.png)

管理レコードに情報が転記されたことが確認できます。

### 「掲示板」にアクセスしたユーザがまだ既読のついていないユーザだった場合、「掲示板管理」で記録する
下記の順で処理を記述していきます。
1. 管理テーブルからClassAとレコードIDが一致するレコードを取得する
1. ClassBに入っているユーザ情報を取得しListを作成する
1. 自分のユーザIDが存在しない場合は、Listに追加する
1. 追加したリストを管理レコードのClassBにUpdateする
1. 自分が存在した場合は何もしない

条件は「画面表示時の前」を指定します。
```Javascript
if(context.Action === 'edit') {
    let data = {
        "View": {
            "ColumnFilterHash": {
                "ClassA": model.ResultId
            }
        }
    };
    let results = items.Get(511, JSON.stringify(data));
    for (let item of results) {
        context.Log(`${item.ClassA},${item.ClassB}`);
        let classBList = JSON.parse(item.ClassB || "[]");
        if (!classBList.includes(context.UserId.toString())) {
            classBList.push(context.UserId.toString());
            context.Log(`更新後のClassBリスト: ${JSON.stringify(classBList)}`);

            let updateData = {
                ClassHash: {
                    ClassB: JSON.stringify(classBList)
                },
            };

            items.Update(item.ResultId, JSON.stringify(updateData));
            context.Log(`ClassBが更新されました。`);
        } else {
            context.Log(`あなたは既読済みです。`);
        }
    }
}
```
画面表示の前を条件にしていますが、一覧画面で動作する必要はないので、context.Actionで編集画面を指定します。
まずは管理テーブルのClassAに対してIDで絞り込みを行います。
次に取得したレコードのClassBをパースしてListを作成します。
この際、もしListに自分のIDがなければListに追加します。
最後にListの内容を管理レコードに更新します。
これにより、自分のIDは既読チェックされたことがわかります。
- Before
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551590/534024e7-70c0-2b60-9626-d6bbd3806daf.png)

- After(高橋ユーザで既読を付けた場合)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551590/912840b9-1c99-33ee-9576-43dd62075d62.png)


## 今回使用したサーバスクリプトまとめ
今回はitems.Upsertとitems.Updateを主に使用しました。
- [開発者向け機能：JSONデータレイアウト：Item](https://pleasanter.org/ja/manual/api-item)
- [開発者向け機能：サーバスクリプト：items.Upsert](https://pleasanter.org/ja/manual/server-script-items-upsert)
- [開発者向け機能：サーバスクリプト：items.Update](https://pleasanter.org/ja/manual/server-script-items-update)

## まとめ
サーバスクリプトを活用することで、このように簡単に既読管理をすることができます。
今回は「既読管理」に焦点を当てましたが、拡張していくことでより複雑な処理も可能です。
例えば全員に既読がついたら管理レコードの状況を完了に変更し、管理者に通知をする。など....
ほかにもレコード本体に現在の既読数を表示することで視覚的にわかりやすくするのもいいかもしれません。
ぜひ、サーバスクリプトを活用してみてください！