GASを使ってサーバレスな採点アプリケーションを作った

大学の副手でプログラミングの採点をしているが,GASでその手間を減らすアプリケーションを作ることができた

その際にGASのイディオムを結構覚えたのでメモ.

アプリケーションの主な仕様

  • Googleフォームから採点するファイルをアップロードする
  • zipファイルの解凍,採点者ごとの担当を決めフォルダの再配置が自動で行われる
  • 採点用シートを自動作成
  • 採点完了後に踏むことでcsv書き出し,ダウンロードができるリンクを作成
  • 採点シート,各採点者ごとのフォルダ,ダウンロードリンクをSlack通知

Googleフォームから採点するファイルをアップロードする

Googleフォームではファイルのアップロード機能がついており,GASのhookと組み合わせることでフォームの送信ごとに自動でファイル処理を行うことができる.

f:id:cohalz:20180413215603p:plain
ファイルに対しても細かく条件をつけることができる

f:id:cohalz:20180413215655p:plain
フォームのhookを設定できる

hookでフォームから投稿されたファイルを扱うには下のようにすれば良い.

function submitForm(e) {
  const itemResponses = e.response.getItemResponses();

  const fileId = itemResponses.filter(
    function(itemResponse){ 
      return itemResponse.getItem().getTitle() == "質問名";
    })[0].getResponse();
  const file = DriveApp.getFileById(fileId).getName();
}

フォームに投稿されたファイルはフォームが置いてあるディレクトリ以下の,

#{フォーム名}(File responses)/#{質問名}(File responses)に保存されている.

ここで注意しないといけないのは,アップロードされたファイルは元のファイル名に加えアップロードした人の名前が追加されていることである.

fugaというユーザがhoge.zipというファイルをアップした際,

ファイル名はhoge - fuga.zipとなるため注意が必要である.

zipファイルの解凍,採点者ごとの担当を決めフォルダの再配置が自動で行われる / 採点用シートを自動作成

GASにはunzipcreateFileなど,Drive上でファイルを扱うメソッドが用意されていて簡単だった.

振り分け後,担当者と学籍番号のペアを返しスプレッドシートに書き込む.

f:id:cohalz:20180413225147p:plain
残りの点数とコメントを担当者がそれぞれ書き込む

採点完了後に踏むことでcsv書き出し,ダウンロードができるリンクを作成

ここはhookではなくGASから「Webアプリケーションとして公開」を利用した.

固定のURLにファイル名のパラメータを付けてアクセスすることで,対応するシートの情報からcsvをエクスポートするリンクを表示する実装になっている.

ファイルダウンロードはこれを参考にした. googleappsscript.hatenablog.com

これにurlパラメータと埋め込みを利用することで動的にシートやファイルを変更できるようになった.

function doGet(e) {
  var html = HtmlService.createTemplateFromFile("dialog");
  html.sheetName = e.parameter.fileName;
  html.fileName = e.parameter.fileName + ".csv";

  return html.evaluate();
}
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script type='text/javascript'>    
      function handleDownload() {
        var sheetName = <?= sheetName ?>;
        var content = <?= export(sheetName); ?>;
        var blob = new Blob([, content ], { "type" : "text/csv"});
        document.getElementById("download").href = window.URL.createObjectURL(blob);
      }
  </script>
  </head>
  <body>
    <a id="download" href="#" download="<?= fileName ?>" onclick="handleDownload()">ダウンロード</a>
  </body>
</html>

採点シート,各採点者ごとのフォルダ,ダウンロードリンクをSlack通知

GASにはGETやPOSTを行うメソッドもあるためSlackのwebhookを用意するだけで通知ができる.

qiita.com

スプレッドシートリンクを共有する際,getUrl()では前回アクティブだったシートが開かれてしまうため,指定したいときは下のようにgidも付けてURLにする必要がある.

function getSheetUrl(sheetName){
  const spreadSheet = SpreadsheetApp.openById(globalVariables().spreadSheetId);
  const sheet = spreadSheet.getSheetByName(sheetName);

  return spreadSheet.getUrl() + '#gid=' + String(sheet.getSheetId());
}

また,GASには環境変数がないため,分離したいものを以下のようにまとめて参照している.

function globalVariables(){
  return {
    spreadSheetId: '',
    rootFolderId: '',
    webappUrl: '',
    slackUrl: ''
  }
}

動作

フォームからzipファイルをアップロードすることでこのようなSlack通知が流れるようになる.

f:id:cohalz:20180413224141p:plain
実装したSlack通知

雑感

サーバレスというとLambdaが話題になりがちだけど,スプレッドシートやフォーム,ドライブを簡単に扱えるGASでも色々できそう.

それに加えて引き継ぎが必要な小規模グループだとAWSはアカウントや課金周りで相性悪い気がする. github.com