GoogleAppsScriptでConfluenceのページを定期的に更新


はじめに

Confluence」はAtlassianが提供する共有ワークスペース。
現在、社内の情報共有の場として、使用していますが、
アドインや提携しているサービスが豊富で、自由度は無限大!!のように感じます。

Confluenceのページ定期更新にいたる背景

とある先輩社員Nさんのつぶやきから、始まりました…。

Nさん:「コンフルのページにイベントまで○○日みたいなカウントダウンのやつ欲しいんだけどー」

私:「イイネ!!やってみよう!(htmlマクロあるっぽいし、Javascriptでおけでしょ)」

--- 問題発生 ---

  • 社内で使用しているクラウド版コンフルでは、「htmlマクロ」が使えない?
  • クラウド版でも代替のアドインがあった!だが…私はコンフルの管理者権限を持っていないので、勝手に追加はできない…。(しかも、こんなことのために管理者様の手を煩わせるわけにはいかない…)

--- かすかな希望 ---

  • コンフルにはAPI(GET,POST,PUT,DELETE)が存在する。
  • 個人単位でAPIキーが発行できる。(管理者様の手を煩わせず、1人で完結できる!)
  • 1日毎に定期更新すれば、あたかも毎日勝手にカウントダウンしているように見せれる!?

Nさん:「無理そうならいいやー、ちょっと言ってみただけー」

(無理なことなんてない、かすかな希望があるんです)
APIをたたくスクリプトを用意して、1日おきに定期実行で該当箇所更新させたる!

て、ことで、長くなりましたが、
Google Apps Script(以下GAS)で、コンフルAPIをたたいて、ページを更新させたいとなりました。
加えて、定期実行も!(GASをチョイスしたのは、定期実行が簡単に設定できるからです。※1)

※1 後述しますが、毎日の定期実行が簡単に設定できるのは、1時間単位。
  なので、0時ぴったりなど、クリティカルな時間調整が必要な場合には向いていません。

やってみよう

ConfluenceRESTAPIドキュメント:https://developer.atlassian.com/cloud/confluence/rest/

1.APIキーの取得

まずは、ATTLASSIANアカウント管理ページに遷移し、「APIトークンを作成する」をクリック。

その後、ラベルに任意の値を入力して、「作成」をクリック。

作成後、2度と見れないからなとかなり脅されるので、黙ってコピーして、保管する。

2. GASにスクリプトを記述

○ソースコード1

以下の3点を認証ヘッダに付与してAPIリクエストを行うので、定義&ヘッダ作成関数を用意する。

  • APIの対象となるワークスペース
  • アクセスに使用するユーザー
  • APIキー
コード.gs
// API情報を定義
// APIで表示及び更新したいコンフルのワークスペース
var API_BASE_URL = 'https://xxxxxxxxx/wiki'; 
var user_id = 'メールアドレス';
var password = '1.で取得したAPIキー';

// 更新対象のページIDを定義
var page_id = '111111111';

/* 認証ヘッダー作成関数 */
function create_headers(user_id, password) {
  return {
    'content-type'  : 'application/json',
    'Authorization' : 'Basic ' + Utilities.base64Encode(user_id + ':' + password)
  };
}
○ソースコード2

GET時のパラメータであるexpandはGET時に何を取得するかをカンマ区切りで指定する。

キー 取得するもの
space 取得対象のページが所属するスペース
version 取得対象のページのバージョン
history 取得対象のページの履歴
body 取得対象のページ本文
コード.gs
/* コンフルのGETAPI呼び出し関数 */
function get_previous_content(headers, page_id, expand_string) {
  var options = {
    'headers'  : headers,
    'method'  : 'get'
  };
 
  // 記事内容を取得
  var api_url      = API_BASE_URL + '/rest/api/content/' + page_id + '?expand=' + expand_string;
  var response     = UrlFetchApp.fetch(api_url, options).getContentText('UTF-8');
  var content_json = JSON.parse(response);

  return content_json;
}

/* コンフルのPUTAPI呼び出し関数 */
function put_content(headers, page_id, current_version, new_page_title, new_page_body, expand_string) {
  var new_version = current_version + 1; // バージョンを更新
  // 更新内容を定義
  var payload = {
    'type'    : 'page',
    'version' : {'number' : new_version},
    'title'   : new_page_title,
    'body'    : {
      'storage' : {
        'value'          : new_page_body,
        'representation' : 'storage'
      }
    }
  };
  payload = JSON.stringify(payload);

  options = {
    'headers' : headers,
    'payload' : payload,
    'method'  : 'put'
  };

  // 記事内容を更新
  var api_url      = API_BASE_URL + '/rest/api/content/' + page_id;
  var response     = UrlFetchApp.fetch(api_url, options).getContentText('UTF-8');
  var content_json = JSON.parse(response);

  return content_json;
}

○ソースコード3

Mainとなる関数。
現在の記事内容を取得して、
<strong>~日</strong>の部分を1日減算して、ページを更新する処理を定義する。
正規表現の部分を変更すれば、どんな箇所でも更新可能です。

コード.gs
/* 記事を更新する関数 */
function updateContent() {
  // 現在の記事内容を取得
  var headers      = create_headers(user_id, password);
  var prev_content = get_previous_content(headers, page_id, 'body.storage,version');

  // 記事内容を変更
  var pattern_match = prev_content.body.storage.value.match(/<strong>([\s\S]*?)日<\/strong>/);

  // 数値部分を抜粋
  var day = parseInt(pattern_match[0].replace(/[^0-9^\.]/g, ""), 10);
  // 0よりも大きければ、日数を減算
  if (day > 0) {
    day -= 1;
    // 更新後コンテンツを定義
    var new_page_content = prev_content.body.storage.value.replace(/<strong>([\s\S]*?)日<\/strong>/, "<strong>" + day + "日</strong>");
    // 更新
    var content_json = put_content(headers, page_id, prev_content.version.number, prev_content.title, new_page_content, null);
  }
}

3. スクリプトを実行

実行関数にupdateContentを指定して実行!!

意図したページになっているかを確認。

4. GASを定期実行する。

赤枠の「トリガー」をクリックして、トリガー設定画面に進む。

トリガーを追加をクリックして、トリガーの詳細を設定。

今回の詳細は、
updateContent関数を1日に1回午前0時~1時の間に実行する。
午前0時~1時の間に」→この部分が前述したGASがクリティカルな時間調整が必要な場合には向いていない理由
何分に実行するかどうかまでは、指定できません。

これで、定期実行設定完了!
あとは、明日の実行結果を待つのみ。

まとめ

  • コンフルに管理者権限等がなくてもAPIキーは発行できるので、個人ベースでAPIを使用できる。
  • GASの記法はほぼJavascriptなので、学習コストが抑えられる。
  • GASでhtmlを扱うのは少々困難。(私が正規表現苦手なだけ…??何度もデバックして確認しました…。)
  • GASなら定期実行も簡単にできる。
  • 間違っても、定期実行で1分おきとかにしないように!!(通知を受けている人がいると、えらいことに…。)