ワークフロー承認後にファイル管理へファイルを登録する

目次

はじめに

ワークフロー申請を承認したときのイベント を使い、ワークフローの申請内容をファイル管理に登録します(ファイルを登録する部分は Garoon SOAP API を使用しています)。

前提条件と注意事項

  • このカスタマイズには、クラウド版 Garoon またはパッケージ版 Garoon 4.10 以降の環境が必要です。
  • ワークフロー JavaScript カスタマイズは、JavaScript を適用した後に申請されたワークフローが対象です。
    それ以前に申請されたワークフローには適用されません。
  • 代理承認時にカスタマイズが動作しない不具合を確認しています。(2019/2/21 追記)

できること

社内規程のような公文書など、登録する際に承認が必要となるファイルの登録を、承認ワークフローと連携させることができます。
申請時にファイルを複数登録することで、最大 5 つまで同時に承認を申請できます。

完成イメージ

Garoon のワークフローで承認すると、申請内容がファイル管理に登録されます。

  • 「承認する」ボタンをクリックすると、ワークフローの内容がファイル管理の特定のフォルダーに登録されます。

ファイルの登録にはワークフロー側に JavaScript ファイルを設定しカスタマイズを行います。
また、ファイル管理の登録先フォルダーには承認者による書込み権限が必要となります。

Garoon ワークフローの設定手順

ワークフローの項目の内容は、会社によって異なります。
ここでは、サンプルということで、ファイル管理へ登録可能な項目をおおむね網羅した申請フォームに JavaScript/CSS カスタマイズを設定する流れを説明します。

ワークフローの申請フォームを作成する

まずは以下の項目を配置して、ワークフローの申請フォームを作成していきます。
申請フォームの作成方法については、Garoon ヘルプ - 申請フォームの作成の流れ クラウド版 (External link) パッケージ版 (External link) を参照してください。

申請フォームは、ファイル管理の項目と対応付けます。それぞれの項目は以下のとおり設定してください。
項目コードは、JavaScript コード内でそれぞれの項目を指定するための一意の文字列になります。

項目名 項目タイプ 項目コード 必須 備考
ファイル1 ファイル添付 Attach1 最大ファイル数を1に設定します。
タイトル1 文字列(1行) Title1
説明1 文字列(1行) Description1
ファイル2 ファイル添付 Attach2 最大ファイル数を1に設定します。
タイトル2 文字列(1行) Title2
説明2 文字列(1行) Description2
ファイル3 ファイル添付 Attach3 最大ファイル数を1に設定します。
タイトル3 文字列(1行) Title3
説明3 文字列(1行) Description3
ファイル4 ファイル添付 Attach4 最大ファイル数を1に設定します。
タイトル4 文字列(1行) Title4
説明4 文字列(1行) Description4
ファイル5 ファイル添付 Attach5 最大ファイル数を1に設定します。
タイトル5 文字列(1行) Title5
説明5 文字列(1行) Description5

上記のとおり設定が完了したら、土台となる申請フォームの作成は完了です。

Javascript/CSSファイルを適用する

申請フォームの作成が完了したので、ここから作成した申請フォームに JavaScript ファイルを適用していきます。

適用ファイルの準備

今回はサンプルということで、登録先のフォルダーを固定しています。まずは登録先のフォルダーを決定します。
ファイル管理から、登録したいフォルダーにアクセスします。URL に含まれる hid(フォルダーID)を確認します。のちほどプログラムの書き換えに使いますので、メモしておきましょう。

例:以下のイメージでは、登録するフォルダー「改定資料」にアクセスした際の URL が https://{subdomain}.cybozu.com/g/cabinet/index.csp?hid=20 のため、フォルダーID は[20]になります。

次のサンプルコードをエディタにコピーします。
15 行目の HID を先ほどメモしたフォルダーID に書き換えます。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/**
 * Garoon JavaScript、SOAP APIを使ったサンプルプログラム
 *
 * 「wf_to_doc.js」ファイル
 *
 * Copyright (c) 2018 Cybozu
 *
 * Licensed under the MIT License
 */
(($) => {
  'use strict';
  /**
   * 登録先フォルダID
   */
  const HID = 2;

  /**
   * 共通SOAPコンテンツ
   * ${XXXX}の箇所は実施処理等に合わせて置換して使用
   */
  const SOAP_TEMPLATE =
        '<?xml version="1.0" encoding="UTF-8"?>' +
        '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">' +
          '<soap:Header>' +
            '<Action>${ACTION}</Action>' +
            '<Timestamp>' +
              '<Created>${CREATED}</Created>' +
              '<Expires>2037-08-12T14:45:00Z</Expires>' +
            '</Timestamp>' +
            '<Locale>jp</Locale>' +
          '</soap:Header>' +
          '<soap:Body>' +
            '<${ACTION}>' +
              '${PARAMETERS}' +
            '</${ACTION}>' +
          '</soap:Body>' +
        '</soap:Envelope>';

  /**
   * ドキュメント登録パラメータテンプレート
   * ${XXXX}の箇所は入力値等で置換して使用
   */
  const DOC_ADD_TEMPLATE =
        '<parameters hid="${HID}" name="${FILE_NAME}" title="${TITLE}" description="${DESCRIPTION}">' +
          '<request_token>${REQUEST_TOKEN}</request_token>' +
          '<content xmlns="">' +
            '${FILE_CONTENT}' +
          '</content>' +
        '</parameters>';

  // 文字列をHTMLエスケープ
  const escapeHtml = function(str) {
    return str
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#39;');
  };

  // リクエストトークン取得
  const getRequestToken = function() {
    const defer = $.Deferred();

    // リクエストトークンの取得
    let tokenRequest = SOAP_TEMPLATE;
    tokenRequest = tokenRequest.replace('${PARAMETERS}', '');
    tokenRequest = tokenRequest.split('${ACTION}').join('UtilGetRequestToken');
    tokenRequest = tokenRequest.replace('${CREATED}', luxon.DateTime.utc().startOf('second').toISO({suppressMilliseconds: true}));
    $.ajax({
      type: 'post',
      url: '/g/util_api/util/api.csp',
      cache: false,
      async: false,
      data: tokenRequest
    })
      .then((respForToken) => {
        defer.resolve($(respForToken).find('request_token').text());
      });
    // 本来はエラー処理を実施
    return defer.promise();
  };
  // 指定した申請情報から添付ファイル情報を取得
  const getRequestFiles = function(requestId) {
    const defer = $.Deferred();
    let request = SOAP_TEMPLATE;
    request = request.replace('${PARAMETERS}',
      '<parameters><application_id>' + requestId + '</application_id></parameters>');
    request = request.split('${ACTION}').join('WorkflowGetReceivedApplicationsById');
    request = request.replace(
      '${CREATED}', luxon.DateTime.utc().startOf('second').toISO({suppressMilliseconds: true}));
    $.ajax({
      type: 'post',
      url: '/g/cbpapi/workflow/api.csp',
      cache: false,
      async: false,
      data: request
    })
      .then((response) => {
        defer.resolve($(response).find('files_item'));
      });
    // 本来はエラー処理を実施
    return defer.promise();
  };
  // 指定IDのファイルを取得
  const downloadFile = function(fileElements) {
    const defer = $.Deferred();

    let request = SOAP_TEMPLATE;
    request = request.replace('${PARAMETERS}',
      '<parameters file_id="' + fileElements.fileId + '"></parameters>');
    request = request.split('${ACTION}').join('WorkflowFileDownload');
    request = request.replace(
      '${CREATED}', luxon.DateTime.utc().startOf('second').toISO({suppressMilliseconds: true}));
    $.ajax({
      type: 'post',
      url: '/g/cbpapi/workflow/api.csp',
      cache: false,
      async: false,
      data: request
    })
      .then((response) => {
        fileElements.fileContent = $(response).find('content').text();
        defer.resolve(fileElements);
      });
    // 本来はエラー処理を実施
    return defer.promise();
  };

  // ワークフロー承認イベントで起動する
  // 申請内容をファイル管理に登録する
  garoon.events.on('workflow.request.approve.submit.success', (event) => {
    // 申請内容を取得する
    const request = event.request;

    return getRequestToken().then((requestToken) => {
      const requestId = request.id;
      // 申請 ID から添付されたファイル情報を取得
      return getRequestFiles(requestId).then(($requestFileItem) => {
        const files = {};
        $requestFileItem.each((_index, fileItem) => {
          const itemName = $(fileItem).attr('name');
          const file = $(fileItem).find('file');
          files[itemName] = {
            id: $(file).attr('file_id'),
            name: $(file).attr('name')
          };
        });
        for (let i = 1; i <= 5; i++) {
          const file = files['ファイル' + i];
          if (!file || !file.id) {
            continue;
          }
          // 申請内容から登録内容を取得
          const fileElements = {
            title: request.items['Title' + i].value,
            description: request.items['Description' + i].value,
            fileName: file.name,
            fileId: file.id
          };

          downloadFile(fileElements).then((fileElementsPlus) => {
            const title = fileElementsPlus.title;
            const description = fileElementsPlus.description;
            const fileName = fileElementsPlus.fileName;
            const fileContent = fileElementsPlus.fileContent;

            let docAddParam = DOC_ADD_TEMPLATE;
            docAddParam = docAddParam.replace('${REQUEST_TOKEN}', escapeHtml(requestToken));
            docAddParam = docAddParam.replace('${HID}', HID); // フォルダID
            docAddParam = docAddParam.replace('${TITLE}', title); // タイトル
            docAddParam = docAddParam.replace('${DESCRIPTION}', description); // 説明
            docAddParam = docAddParam.replace('${FILE_NAME}', fileName); // ファイル名
            docAddParam = docAddParam.replace('${FILE_CONTENT}', fileContent); // 添付ファイルのbase64Binary表現

            let docAddRequest = SOAP_TEMPLATE;
            // SOAPパラメータを完成させる
            docAddRequest = docAddRequest.replace('${PARAMETERS}', docAddParam);
            // 実行処理を指定
            docAddRequest = docAddRequest.split('${ACTION}').join('CabinetAddFile');
            docAddRequest = docAddRequest.replace(
              '${CREATED}', luxon.DateTime.utc().startOf('second').toISO({suppressMilliseconds: true}));

            // ファイル管理への登録実行
            $.ajax({
              type: 'post',
              url: '/g/cbpapi/cabinet/api.csp',
              cache: false,
              async: false,
              data: docAddRequest
            });
            // 本来はエラー処理を実施
          });
        }
      });

    });
  });
})(jQuery.noConflict(true));

ファイル名を「wf_to_doc.js」、文字コードを「UTF-8」で保存します。
ファイル名は任意ですが、ファイルの拡張子は「js」にしてください。

tips
補足

ワークフロー申請フォームでは、ユーザを選択する項目タイプがありません。
そのため、今回のサンプルでは、文字列(複数行)項目に対して選択ユーザを追加するカスタマイズを行います。

JavaScript/CSSファイルとして使用するファイルおよびリンクの追加
  1. 「申請フォーム情報」部分の右端にある「JavaScript / CSS によるカスタマイズ」をクリックします。

    申請フォームの詳細画面に「JavaScript / CSS によるカスタマイズ」というリンクが表示されない場合、
    ワークフローのカスタマイズが許可されていない場合はリンクが表示されませんので、Garoon ヘルプ - ワークフローのカスタマイズを許可する クラウド版 (External link) パッケージ版 (External link) を参照してください。

  2. [カスタマイズ]項目に「適用する」を選択します。wf_to_doc.js が使用する jQuery、Luxon、および作成した「wf_to_doc.js」ファイルを追加し、「設定する」をクリックします。

本カスタマイズでは、 Cybozu CDN の以下のライブラリーを使用します。

  • jQuery
    https://js.cybozu.com/jquery/3.6.4/jquery.min.js
  • Luxon
    https://js.cybozu.com/luxon/3.3.0/luxon.min.js

jQuery と Luxon は wf_to_doc.js より上位に登録してください。

以上ですべての設定は完了です。最初にお見せした完成イメージのとおり、動けば成功です。

おわりに

Garoon API のカスタマイズサンプル ワークフローとファイル管理との連携方法を紹介しました。
ワークフローの承認実行のタイミングで Garoon 内の別アプリにデータを登録することが簡単にできます。

更新履歴

  • 2022 年 2 月 1 日
    添付ファイルの ID を取得する処理を、workflow.request.approve.submit.success イベントのワークフローオブジェクトを使う方法から、 SOAP API(受信した申請を取得する) を使う方法に変更
information

この Tips は、2023 年 4 月版 Garoon で動作を確認しています。