17
13

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 5 years have passed since last update.

鍵管理システムを作ったら褒められた話

Last updated at Posted at 2018-11-17

#作りたいもの
筆者の所属団体で、鍵の借用時と返却時にボタンを押すことでログが残り、任意のタイミングで利用状況を確認できるシステム
##今まで
鍵の管理用のLINEグループでいちいち借用返却報告をしてた
→通知うざいっす
#使ったもの
プラットフォームは今まで通りLINEで
→MessagingAPIとGASでLINE bot
#概要
LINE botにキーワードを送信するとGASを動かしてspreadsheetに入力
確認用のキーワードを送信するとspreadsheetを参照して利用状況を返信してくれる
IMG_5131.jpg
##MessagingAPIの登録
たくさん投稿があると思うので割愛
LINE Developers
RichMenuを使うことでユーザーにキーワードをミスなく入力させる事ができる。
アクセストークンを控えておく。

##GAS
新しいGASのファイルとlog用のspreadsheetを作る。
作ったGASファイルのリンクをLINE Developersの方でwebhookに貼り付ける。

key.gs
var CHANNEL_ACCESS_TOKEN = '***LINE ACCESS TOKEN***';
var url = "***SHEET URL***";
var spreadsheet = SpreadsheetApp.openByUrl(url);

var sheets = spreadsheet.getSheets(); //log用のシート

function getUserName(UID){//Userの表示名取得
  var url = 'https://api.line.me/v2/bot/profile/' + UID;
  try {//エラー処理
    var response = UrlFetchApp.fetch(url,{
      'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN,
      }
    })
  }catch(e){//表示名を取得できなかったら
    return 0;
  }
 var json = JSON.parse(response.getContentText());
 return json["displayName"]
}


function makeMsg(array){//返信用メッセージを作るやつ
  var result=[];
  for(var i=0;i<array.length;i++){
    if (array[i] !== "closed"){
      var temp = array[i].split(',');
      result[i]=temp[1]+"\n"+temp[0];
    } else {
      result[i]=array[i];
    }
  }

  var msg = "利用状況\n"+
            "*************\n"+
            "ボックス:" + result[0] + "\n"+
            "会議室 : " + result[1] +"\n"+
            "2北 : " + result[2];
  return msg;
}



function sendMsg(reply_token,message){ //メッセージ送信
  var url = 'https://api.line.me/v2/bot/message/reply';
  UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'replyToken': reply_token,
      'messages': [{
        'type': 'text',
        'text': message,
      }],
    }),
  });

}



function deleteRows(sheets){ //行削除(なくてもいい)
    for(var i in sheets){
        var LastRow = sheets[i].getLastRow()
        if(LastRow > 6) {
          sheets[i].deleteRow(2)
        }
    }
}

function updateSheet(room,key,value){ //sheetの操作
   if (key == 'take'){

    var data = sheets[room].getDataRange().getValues();
    var lastrow = data.length;
    if(data[lastrow-1][1]==""){
      lastrow = lastrow - 1;
    }
    sheets[room].getRange(lastrow + 1, 1).setValue(value);

  } else if (key == 'return'){

    var lastrow = sheets[room].getDataRange().getLastRow();
    sheets[room].getRange(lastrow, 2).setValue(value);
  }

}


function doPost(e) { //イベントがあったら動く関数

  var date = new Date();
  var event_data = JSON.parse(e.postData.contents).events[0]
  var reply_token= event_data.replyToken;

  if (typeof reply_token === 'undefined') {
    return;
  }

  var message = JSON.parse(e.postData.contents).events[0].message.text.split('-');
  var user_id = JSON.parse(e.postData.contents).events[0].source.userId;
  var user_name = getUserName(user_id);
  var value = Utilities.formatDate( date, 'Asia/Tokyo', 'yyyy/MM/dd HH:mm') + "," + user_name + "," + user_id;
  var msg = "OK!";

  if (message[0] == "box"){

    updateSheet(0,message[1],value)

  } else if (message[0] == "meeting"){

    updateSheet(1,message[1],value)

  } else if (message[0] == "warehouse"){

    updateSheet(2,message[1],value)

  } else if (message[0]=='ログ'){

    msg = url;

  } else if (message[0]=='id'){

    msg = user_id;

  } else if (message[0]=='かぎ'){

    var data_list = [];
    for(var i in sheets){
      var sheet_data = sheets[i].getDataRange().getValues();
      var lastrow = sheet_data.length;
      if(sheet_data[lastrow-1][1]==""){
        data_list[i] = sheet_data[lastrow-1][0];
      } else{
        data_list[i] = "closed";
      }
    }
    msg=makeMsg(data_list);

  } else if(message[0] == 'ヘルプ'){

    msg = "";

  } else {
    msg = "I'm sorry. I can't reply.";

  }

  deleteRows(sheets);
  sendMsg(reply_token,msg);

  return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);

}



function remind(){//リマインド関数

  var status_dict = {box:"", meeting:"", warehouse:""};
  var key = Object.keys(status_dict);
  for(var i in sheets){
    var sheet_data = sheets[i].getDataRange().getValues();
    var lastrow = sheet_data.length;
    if(sheet_data[lastrow-1][1]==""){
      status_dict[key[i]] = sheet_data[lastrow-1][0].split(',')[2];
    } else{
      status_dict[key[i]] = "";
    }
  }
  for(var key in status_dict){
    var text = remindMsg(key);
    if(!(text =="")){
      push(status_dict[key],text);
    }
  }
}



function remindMsg(key){//セリフ作成
  var text = "";
  if(key =="box"){
    text = "ボックス";
  } else if(key =="meeting") {
    text = "会議室";
  } else if(key =="warehouse") {
    text = "2北";
  }
  return text + "の鍵は返却しましたか?返却済でしたら返却ボタンを押下してください。";
}



function push(user,text){//PUSHメッセージ送信
  var url = "https://api.line.me/v2/bot/message/push";
  var headers = {
    "Content-Type" : "application/json; charset=UTF-8",
    'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN,
  };
  var postData = {
    "to" : user,
    "messages" : [
      {
        'type':'text',
        'text':text,
      }
    ]
  };
  var options = {
    "method" : "post",
    "headers" : headers,
    "payload" : JSON.stringify(postData),
    "muteHttpExceptions": true
  };

  //return UrlFetchApp.fetch(url, options);
  var response = UrlFetchApp.fetch(url, options);
}

参考:
LINE Botをサーバーレスで開発!Google Apps ScriptとLINE Messaging APIを使ってチャットボットを作ってみた
GASでSpreadsheetを操作する自分的ベストプラクティス
transpose 2-dimensional Javascript array in one line

#完成品
借りたり返したり
IMG_5138 2.PNG
開いてたり閉まってたり
LINE_capture_564165717.282180.JPG

#所感
今まで自己満というか遊びというかでプログラミングしてて、初めて人のためにモノを作ったんですが悪くないですね。通知から解放された友人に褒められました。
GAS(JavaScript)を触った事がなかったので(これでいいのか…???)感は否めないですが、突貫工事の割にちゃんとしたものができてよかったです。
ここをこうしたら速くなるよ!とか、こう書いた方がわかりやすい/JSではこういう作法!とかコメントいただけましたら幸いです。

おしまい

2019/06/07 GASのコードを更新しました

17
13
8

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
17
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?