Confluenceの添付ファイル一覧出力をGASとSpreadSheetのみで試してみた

Confluence上の添付ファイル一覧出力をGASとSpreadSheetだけで完結できないかと試してみました。分量が多い場合はタイムアウトとの戦いになります。
2022.04.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Confluenceにはまとめてページをエクスポートできる機能があるものの、何かしらの要因で失敗することも多くあります。

考えられるものとしては以下の通り。

  1. サイズ量
  2. 用いたマクロ
  3. 拡張独自記法

2と3に該当する場合はどうしようもないという感想なのですが、1の場合は添付ファイル削除等の手の打ち様があります。

ただ、ページ数が多い場合には添付ファイル一覧の可視化も大変です。手段としては以下の記事もあるのですが、GAS+SpreadSheetでやれば環境に依存しないなと思い、試してみました。

SpreadSheet上へダンプする

以下のコードをSpreadSheetのApps Scriptに貼り付けます。

// API情報を定義
// APIで表示及び更新したいコンフルのワークスペース
var BASE_URL = 'https://XXX.atlassian.net'; 
var user_id = 'XXXXX';
var password = 'XXXXXXXXXXXXXXXXXXXX';
var space_key = 'XXX'

function onOpen() {
  SpreadsheetApp
    .getActiveSpreadsheet()
    .addMenu('Confluenceステータス取得', [
      {name: 'ページ一覧取得', functionName: 'set_page_id'},
      {name: '添付一覧取得', functionName: 'dump'},
    ]);
}

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

function call(path) {
    var next_link = path
    var results = [];
    while (next_link) {
      try {
        var response = UrlFetchApp.fetch(BASE_URL + '/wiki' + next_link, create_headers(user_id, password))
        var responseText = response.getContentText()
        var parsedText = JSON.parse(responseText)
        next_link = parsedText["_links"]["next"]
        results = results.concat(parsedText["results"])
      } catch(e) { }
    }
    return results;
}

function get_pages_for() {
  return call("/rest/api/space/" + space_key + "/content/page")
}

function get_attachments_for(page) {
  return call("/rest/api/content/" + page + "/child/attachment")
}

function set_file_status(filelist) {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getSheetByName("添付ファイル")
  sheet.getRange(2,1,filelist.length, filelist[0].length).setValues(filelist)
}

function set_page_id(source) {
  var source = get_pages_for()
  var id_list = []
  for (var page_index in source) {
    var page = source[parseInt(page_index)]
    id_list.push([page["id"], page["title"], page["_links"]["webui"]])
  }
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getSheetByName("ページ")
  sheet.getRange(2,1, id_list.length, id_list[0].length).setValues(id_list)
  sheet.getRange(1,id_list[0].length + 1).setValue(id_list.length)
}

function get_page_id_length() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getSheetByName("ページ")
  return sheet.getRange(1,4).getValue()
}

function get_page_status() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getSheetByName("ページ")
  var ids = sheet.getRange(2,1,sheet.getRange(1,4).getValue(), 3).getValues()
  return ids
}

function dump() {    
  var filelist = []
  var source = get_page_status()
  for (var page_index in source) {
    // Get attachments from each page
    var page = source[parseInt(page_index)]
    if (page) {
      var args = get_attachments_for(page[0])
      var attachments = args["attachment"]
      for (var attachment_index in attachments) {
        var attachment = attachments[parseInt(attachment_index)]
        filelist.push([
          page[1], attachment["title"], 
          attachment["extensions"]["fileSize"],  
          BASE_URL + "/wiki" +  page[2]
        ])
      }
    }
  }
  set_file_status(filelist)
}

流れとしては以下の通り。

  1. ページ一覧を取得
  2. 各ページから添付ファイルの情報を取得

ページ一覧取得の処理を独立させた理由は処理時間タイムアウトの可能性をできる限り軽減するためです。

手順は、メニューの「Confluenceステータス取得」から「ページ一覧取得」を実行して、その後「添付一覧取得」を実行します。

成功すると、以下のようにシート上へ出力されます。

マクロ内で「ページ」と「添付ファイル」の2シートを指定していますが、これはマクロ内で追加作成する形にしても問題ありません。

あとがき

ページ分量が少ないスペースだと問題ないのですが、ページ分量が多くなると添付ファイル一覧に大きく時間がかかって失敗しやすいです。対策としては、取得した添付ファイルデータの個数と内容を常に記録しながら進めて、タイムアウトを起こした後はその続きから再開するという手段もあります。今回は結局元となったPythonのバッチに頼ることにしました。

添付ファイル分量が少なく且つGASによるSpreadSheet出力のみで済ませたい場合の参考になれば幸いです。