kintoneアプリに論理削除機能を作ってみた

みなさんこんにちは。[プロジェクト・アスノート](https://pj.asunote.jp/)の松田です。
[サイボウズ公認 kintoneエバンジェリスト](https://www.kintone-eva.com/matsuda-shotaro)、[ラジカルブリッジ公認 カレンダーPlusエバンジェリスト](https://radical-bridge.com/information/calendarPlus-Evangelist-20200901.html)をしています。

[kintone Advent Calendar 2020](https://qiita.com/advent-calendar/2020/kintone)の21日目の記事で公開した、「kintoneアプリにゴミ箱機能を作る」の、コア部分だけを取り出したシンプル版を作ってみました。

豪華版の記事：
[kintoneアプリにゴミ箱機能って欲しくない？｜プロジェクト・アスノート](https://pj.asunote.jp/trushbox_for_kintone_app/)

## 1. 背景
2020年12月現在の kintoneでは、誤って削除したアプリは復旧できるのですが、アプリのレコードに関しては、誤って削除したら二度と戻ってこないということになっています。

そこで、実運用ではご操作によるデータロストを防ぐため、レコードの削除権限は通常与えない、レコード削除はアプリの管理者に連絡をして削除してもらう等の工夫をして運用しているわけです。

データベース的に、どんどん追加されていき、基本的に削除の必要がないようなアプリであればこの運用でも大丈夫なのですが、アプリの種類によって、レコードを削除すること自体が日常的な運用で必要となるケースもあると思います。

そこで、次のようなカスタマイズを考えてみました。

## 2. やりたいこと
* 通常の削除操作を行ったとき、利用者からは普通に削除されたように見える（**自然な削除感**）。
* でも実はレコードは残っていて、アクセス権コントロールにより閲覧できなくなる。

## 3. カスタマイズの方針
* 各削除前イベントでカスタマイズを作動させる。
* 削除操作が行われたとき、削除は実行させずにキャンセル```retuen false```する。
* 同時に、アプリに用意したアクセス権を判定するためのフィールド（削除フラグ）を更新する。

## 4. サンプルアプリ
図のようなサンプルアプリを作成しました。
必要なのは、「削除フラグ（チェックボックスフィールド）」
チェックボックスは、選択肢「削除」を１つだけ設定します。
これを、レコードのアクセス権の判定に使います。
![Cursor_と_アプリの設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87971/d827d452-105f-862c-e43c-d449bb50d877.png)

## 5. レコードのアクセス権設定
削除フラグが「削除」を含むレコードの、everyoneの閲覧権限を外しておきます。
管理者等、ゴミ箱レコードが見えてほしい人がいる場合は、Everyoneの上位に設定してください。
![Cursor_と_レコードのアクセス権.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87971/1375b2f4-002f-085c-e449-e2ae77b17dcf.png)



## 6. JavaScript
```JavaScript
(function() {
  'use strict';

  // 削除前イベント
  const deleteSubmitEvents = [
    'app.record.detail.delete.submit',
    'app.record.index.delete.submit',
    'mobile.app.record.detail.delete.submit'
    ];

  kintone.events.on(deleteSubmitEvents, function(event) {
    // レコード更新データ作成
    const body = {
      'app': kintone.app.getId(),
      'id': event.recordId,
      'record': {
        "削除フラグ": {
          "value": [
            "削除"
          ]
        }
      }
    };
    
    // レコード更新処理
    kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', body).then(function(resp) {
      // 一覧画面に遷移
      location.href = window.location.origin + '/k/' + event.appId + '/';
    });
    return false; // 削除処理をキャンセル
  });
})();

```
## 7. コード解説

### ポイント１　自然な削除感（笑）
一覧画面でのレコード削除は、対象のレコードがすっと消えるという動きをするため、特に問題はなさそうです。
問題は、詳細画面での削除操作後、削除フラグの更新を行うだけだと、
1. 画面表示はレコードが開いたまま
2. 裏で実はレコードが更新されている

となります。

普通にレコードを削除したときの動きとしては、
1. 削除実行操作
2. レコードは削除され、一覧画面に遷移する

という動きになりますので、これを再現したいと思います。

### ポイント２　画面遷移＋削除キャンセルの実装
ちょっとイレギュラーに思える動きをさせています。詳しい方は教えて下さい。
REST APIによるレコード更新処理は非同期処理なので、通常は更新処理のあとに次の操作をしたい場合は、kintone Promiseを使って、次のように書くのだと思います。

```JavaScript
    return kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', body).then(function(resp) {
      // 一覧画面に遷移
      location.href = window.location.origin + '/k/' + event.appId + '/';
      return false; // 削除処理をキャンセル
    });
```
しかし今回、更新後にやりたい処理は画面遷移です。
画面遷移に続いて```return false```は、ちゃんと動作するのか？？

なので、あえてPromiseオブジェクトを返す ```kintone.api()```は```return```せず、非同期処理のままで動作させます。で、非同期を待たずに```return false```を書く。

一覧画面への遷移は、```kintone.api()```の```then```チェーンで実行。

```JavaScript
    kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', body).then(function(resp) {
      // 一覧画面に遷移
      location.href = window.location.origin + '/k/' + event.appId + '/';
    });
    return false; // 削除処理をキャンセル
```
これでなんと、一覧画面への遷移はちゃんと実行され、しかも削除はキャンセルされました。

たぶん、この動作は微妙な感じなので、あまり推奨されるものではないと思います。
自己責任でお試しください、とともに、kintone標準機能で、レコードの復旧処理（ゴミ箱機能）が実装されることを切に願う、２０２０年の年末でした。

## Ex. 初心者向けのライブコーディング動画
kintoneカスタマイズ初心者向けに、上のカスタマイズを作る過程をまるっとライブで行いました。
プログラムを書いていく手順、何をどのように調べながら書いているのか、動かないときはどこをどうやって調べてデバッグしているのか、が超リアルに公開されています（私の実力のなさもまるごと公開されています）。

興味がある方はぜひこちらもご覧ください。そして、チャンネル登録＆高評価よろしくお願いします！
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">突然始まるゲリラライブ。今夜は kintoneカスタマイズ<br>このあと21:40ぐらいから始める予定<br>ドシキンカス ゲリライブ（kintoneアプリに論理削除機能を作る） <a href="https://t.co/fLKXXLpCsR">https://t.co/fLKXXLpCsR</a> <a href="https://twitter.com/hashtag/kintone?src=hash&amp;ref_src=twsrc%5Etfw">#kintone</a></p>&mdash; Shotaro Matsuda（松田正太郎） (@Shokun1108) <a href="https://twitter.com/Shokun1108/status/1341360973958012928?ref_src=twsrc%5Etfw">December 22, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>