1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Tips:SpreadSheetにRememberTheMilkのタスクを取得する

Posted at

何をするのか

  • RememberTheMilkのタスクをスプレッドシートに取得する

なぜするのか

  • GoogleSpreadSheetから何かのAPIを使ってみたかった
  • GrideAppなど連携すると楽しいかもと思った

RememberTheMilk API keyの取得

GAS

設定関連


// AuthParams
var apiKey = "apikey_xxxxxxxxxxxx"
var secret = "secret_xxxxxxxxx"

// SpreadSheetSettings
var spreadsheetId = "spreadsheetid_xxxxxxxxxxxxxx"
var spreadsheetSettingSheetname = "Settings"
var spreassheetOutputSheetname = "Output"  
var spreadsheet = SpreadsheetApp.openById(spreadsheetId)
var sheet = spreadsheet.getSheetByName(spreadsheetSettingSheetname)
var tokenRange = sheet.getRange(1,2)

//requestUrls
var restBaseUrl = "https://api.rememberthemilk.com/services/rest/"
var authBaseUrl = "https://www.rememberthemilk.com/services/auth/"

//Parameters
var listId = xxxxxxx;//取得したいTaskListのId

Mainとなるフロー

  • Taskの取得のフローは下記
    • tokenが切れていたら再度tokenを取得、切れていなければそのままtokenを使う
      • token期限が切れているかを確認 function checkToken(token)
      • frobを取得 function getFlob()
      • frobを使って認証する function auth(flob)
      • frobをtokenに交換(この時点でfrobが破棄される) function getToken(frob)
    • 以降はtokenを使ってapiを呼び出す function getTaskList(token, listId)
  • 定期的にタスクを取得するためには、この関数を定期実行する
    • とりあえず1シートを更新するプログラムになっているが、日付毎にシートを作って履歴管理をするのもありかも
function getTasksFromRtm() {
  
  token = tokenRange.getValue()
  if (checkToken(token) == false){
    //tokenの期限が切れている場合、新しく認証する(URLが表示されるのでブラウザ上でアクセスしたあと、OKボタン)
    var frob = getFrob()
    var authResult = auth(frob)
    var token = getToken(frob)
    tokenRange.setValue(token) //tokenをシートに保持
    }
  var taskList = getTaskList(token, listId)
  //Logger.log(tasks)
  var tasks = taskList[0]["taskseries"]
  toSpreadSheet(spreassheetOutputSheetname, tasks)
  //Logger.log(tasks[0]["taskseries"][0])
}

Module

  • 全体として、API呼び出しをするときのルールがある
    • リクエストパラメータをmd5でハッシュ化したauth_sigを付与する必要がある
    • 例えば、「?method=aaa&list_id=bbb&auth_key=ccc」の場合、下記(※パラメータ名のアルファベット順に並び替えてkeyvalueを連結したもの)をmd5でハッシュ化する。
      • 「auth_keyccclist_idbbbmethodaaa」
    • ハッシュ化したものを「zzzzzz」とすると、最終的なリクエストパラメータは下記となる
      • 「?method=aaa&list_id=bbb&auth_key=ccc&auth_sig=zzzzzz」となる

取得したタスクをスプレッドシートに転記

function toSpreadSheet(outputSheetname, tasks){
  var outputSheet = spreadsheet.getSheetByName(outputSheetname)
  outputSheet.clear()
  
  //転記するサイズ
  var rowSize = tasks.length
  //Header
  outputSheet.getRange(1, 1).setValue("id")
  outputSheet.getRange(1, 2).setValue("title")
  outputSheet.getRange(1, 3).setValue("completed")
  
  for(var i = 1; i < rowSize + 1 ; i++){
    outputSheet.getRange(i+1,1).setValue(tasks[i-1].id);
    outputSheet.getRange(i+1,2).setValue(tasks[i-1].name);
    outputSheet.getRange(i+1,3).setValue(tasks[i-1]["task"][0].completed); //完了の日付
  }  
}

function getFrob() //frobを取得する

  • 今回、taskの取得だけを目指すのでparams=readとしているが、更新や削除したいときはwrite/deleteを使う
function getFrob(){
  //frobをjson形式で取得する
  var methodToGetfrob = "rtm.auth.getFrob"
  var getFrobUrl = restBaseUrl + "?method=" + methodToGetfrob + "&api_key=" + apiKey + "&format=json&perms=read" //読み取りのみ

  var frobSign = secret + "api_key" + apiKey + "formatjson" + "method"+  methodToGetfrob  + "permsread" 
  var encoded = MD5(frobSign)
  getFrobUrl = getFrobUrl + "&api_sig=" + encoded
  
  Logger.log(getFrobUrl);
  var frobJson = UrlFetchApp.fetch(getFrobUrl).getContentText()
  var json = JSON.parse(frobJson);
  if (json["rsp"]["stat"] == "ok") {
    frob = json["rsp"]["frob"]
  }
  Logger.log(frob)
  return frob
}

function checkToken() //tokenが切れているかどうかを取得する

function checkToken(token){

  var methodToCheckToken = "rtm.auth.checkToken"
  var getCheckTokenUrl = restBaseUrl + "?method=" + methodToCheckToken + "&api_key=" + apiKey  + "&auth_token=" + token  +"&format=json" //読み取りのみ
  var checkTokenSign = secret + "api_key" + apiKey+ "auth_token"+ token + "formatjson" + "method"+  methodToCheckToken  
  Logger.log(checkTokenSign)
  encoded = MD5(checkTokenSign)
  getCheckTokenUrl = getCheckTokenUrl + "&api_sig=" + encoded
  
  Logger.log(getCheckTokenUrl)
  var checktokenJson = UrlFetchApp.fetch(getCheckTokenUrl).getContentText()
  var json = JSON.parse(checktokenJson);
  if (json["rsp"]["stat"] == "ok") {
    //tasks = json["rsp"]["tasks"]["list"]
    Logger.log(checktokenJson);
    return true
  }
  Logger.log(checktokenJson);
  return false
}

function getTaskList(token, tasklistId) //taskを取得する


function getTaskList(token, tasklistId){
 
  var methodToGetTask = "rtm.tasks.getList"
  var getTaskUrl = restBaseUrl + "?method=" + methodToGetTask + "&api_key=" + apiKey  + "&auth_token=" + token  + "&list_id=" + tasklistId +"&format=json" //読み取りのみ
  var taskSign = secret + "api_key" + apiKey+ "auth_token"+ token + "formatjson" + "list_id" + tasklist_id + "method"+  methodToGetTask  
  Logger.log(taskSign)
  encoded = MD5(taskSign)
  getTaskUrl = getTaskUrl + "&api_sig=" + encoded
  
  Logger.log(getTaskUrl)
  var taskJson = UrlFetchApp.fetch(getTaskUrl).getContentText()
  var json = JSON.parse(taskJson);
  if (json["rsp"]["stat"] == "ok") {
    tasks = json["rsp"]["tasks"]["list"]
    return tasks
  }
  Logger.log(taskJson);
  return false
}

function auth(frob) //認証する

  • GASだけではうまく認証できなかったので、次のような手順で手動認証
    • tokenが無効の時、認証用のURLをDialogに表示する
    • (手動)認証用のURLをブラウザに貼り付け、アクセス許可をする
    • DialogでOKを押すと以降の処理が進む
//Auth Miyuki Kondo 2020/12/28
function auth(frob){
    
  var authUrl = authBaseUrl + "?api_key=" + apiKey + "&frob=" + frob + "&format=json&perms=read" //読み取りのみ
  var authSign = secret + "api_key" + apiKey + "formatjson" + "frob" + frob + "permsread" 
  encoded = MD5(authSign)
  authUrl = authUrl + "&api_sig=" + encoded
  Logger.log(authUrl);
  
  //下記ではAuthできなかったので、Msgに出るURLを開く形式に。
  //var auth = UrlFetchApp.fetch(authUrl, {method:"post"}).getContentText()
  //Logger.log(auth)
  
  //Authしていない場合は、ブラウザでアクセスして許可、DialogでOKが出るまでWaitする。
  var result = Browser.msgBox(authUrl, Browser.Buttons.OK_CANCEL)
  return true
}

function getToken(frob) //認証する

function getToken(frob){
  //tokenをjson形式で取得する
  var methodToGetToken = "rtm.auth.getToken"
  var getTokenUrl = restBaseUrl + "?method=" + methodToGetToken + "&api_key=" + apiKey + "&frob=" + frob +"&format=json&perms=read" //読み取りのみ
  var tokenSign = secret + "api_key" + apiKey + "formatjson" + "frob" + frob + "method"+  methodToGetToken  + "permsread" 
  encoded = MD5(tokenSign)
  getTokenUrl = getTokenUrl + "&api_sig=" + encoded
  Logger.log(getTokenUrl)
  
  var tokenJson = UrlFetchApp.fetch(getTokenUrl).getContentText()
  var json = JSON.parse(tokenJson);
  if (json["rsp"]["stat"] == "ok") {
    token = json["rsp"]["auth"]["token"]
    Logger.log(tokenJson)
    Logger.log(token)
    return token
  }
  Logger.log(tokenJson)
  return false
}

//MD5を求める関数。下記サイトより拝借。
//https://qiita.com/SogoK/items/cc0d514ffe74009e5fd5
function MD5(input) {
...
}

まとめ

  • 結局AuthをGASだけではできなかった。
  • token保持しておけば毎回認証する必要はないため、定期実行はできそう(GoogleDrive等々にアクセスする際に認証を求められるのと同じ形式かな)
  • (tokenの保持をスプレッドシートにしちゃってるのはどうなのかと思う、、、、)
  • 貼り付けてみたら変数名がキャメルケースとスネークケースがばらんばらんで慌てて直した。jsではキャメルケースが一般的っぽいですかね。
  • もうGASからのAPIコワクナイ
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?