【GAS x AWS】kintoneのゲストユーザーを自動追加したい～GASとAWSを連携してメールを自動処理する～【kintone】

# はじめに
kintoneでシステムを開発したのですが、同システムのゲストユーザーアカウントを希望する人（メールでアカウント申請した人）に自動発行したいと思い立ちました。

開発したシステム: https://qiita.com/Lastonemile/items/65b9102c868e09b3248e

そこで、GAS(Google Apps Script)とAWSを組み合わせて、自動発行することにしました。

# 出来たこと
指定した条件の受信メールを自動取得し、同内容をAWSへ送信しAWSでその内容に沿ってゲストユーザー登録を自動化しました。

# GASの設定
これまで全く利用したことはありませんが、GASの設定はググりながらで比較的すんなり行えました。（ベースはjavascriptのようです）

```
// 初期設定
const HOOK_URL = 'https://xxxxxxxxxxxx';　//AWS(api gateway)エンドポイント

function main() {
  let after = parseInt(((new Date()).getTime() - 5 * 60 * 1000) / 1000);  //5分前の時刻をUNIX時間で取得
  let searchTarget = 'in:inbox subject:"アカウント申請" is:unread after:' + after; //検索条件を指定（after以降で件名「アカウント申請」含む）
  GmailApp
  .search(searchTarget)
  .forEach(function (thread) {
    let resp;
    let mark = false;
    thread.getMessages().forEach(function (message) {
      let subject = message.getSubject();
      resp = send(message);
      resp = JSON.parse(resp)
      mark = true;
      Logger.log(resp);
    });
    if(mark){
      thread.markRead();　//既読に変更
      MailApp.sendEmail({ //AWSの処理結果をメール送信
        to:resp.body.from,
        subject:resp.body.subject,
        body:resp.body.body
      }); 
    }
  });
}

function send(message) {
  let sendText = {
    "title":message.getSubject(),
    "detail":message.getPlainBody()
  }
  let jsonData = {
    "username" : message.getFrom(),
    "text" : sendText
  }
  let options = {
    "method" : "POST",
    "contentType" : "application/json",
    "payload" : JSON.stringify(jsonData)
  };
  let resp = UrlFetchApp.fetch(HOOK_URL, options); //受信内容をAWSへ
  return resp;
}
```

#AWSの設定（kintoneゲストユーザー追加）
大まかな処理の流れとしては、①ゲストユーザーを追加、②現在スペースに紐づけられているゲストユーザーを取得、③追加したゲストユーザーおよび現ゲストユーザーをスペースに紐づけ　以上になります。
＊②については、apiで取得する方法がないようなので、別アプリに登録することで対応しました。

```
const request = require('/opt/aws-layer/node_modules/request');
exports.handler = async (event) => {
    // TODO implement
    const code = extract(event.username,"<",">");
    const reg_mail = /^[A-Za-z0-9]{1}[A-Za-z0-9_.-]*@{1}[A-Za-z0-9_.-]{1,}\.[A-Za-z0-9]{1,}$/;//メールアドレス判定
    if(reg_mail.test(code)){
        const DOMAIN = "kintoneドメイン";
        const headers = {'X-Cybozu-Authorization': 'kintoneのid:pass(base64)','Content-Type': 'application/json','X-Requested-With':'XMLHttpRequest'};
        const pass = pass_create();
        let resp = await requestPromise(kintone_guest(headers,DOMAIN,code,pass));
        let message = resp.message;
        let result;
        if(!message){
            let resp_guest_new = await requestPromise(guest_newuser(headers,DOMAIN,code,pass));
            let resp_guest_get = await requestPromise(guest_get(headers,DOMAIN));
            let member = [];
            for( let i = 0; i < resp_guest_get.records.length; i++ ){
                member.push(resp_guest_get.records[i].MAIL.value);
            }
            let resp_guest_put = await requestPromise(guest_put(headers,DOMAIN,member));
        }
        if(!message){
            message = remessage(code,pass);
        }
        result = {
            from:event.username,
            subject:"ご連絡ありがとうございます",
            body:message
        };
        const response = {
            statusCode: 200,
            body: result,
        };
        return response;
    }
};

//request promise
function requestPromise(param){
    return new Promise((resolve, reject)=>{
        request(param, function (error, response, body) {
            if(error){
                reject("ページを取得できませんでした");
            }else{
                resolve(body);
            }
        })
    })
}

//kintoneゲスト追加
const kintone_guest = function(headers,DOMAIN,code,pass){
    let body = {
        'guests': [
            {
              'code': code,
              'password': pass,
              'timezone': 'Asia/Tokyo',
              'locale': 'ja',
              'name': extract(code,"","@")
            }
        ]
    };
    let BASE_URL = "https://" + DOMAIN + "/k/v1/guests.json";
    let options_postguest = {
        url: BASE_URL,
        method: 'POST',
        headers: headers,
        body: body,
        json: true
    };
    return options_postguest;
}

//ゲスト情報別記
function guest_newuser(headers,DOMAIN,code,pass){
    let url = "https://" + DOMAIN + "/k/v1/record.json";
    let body = {
        'app': "アプリid",
        'record': {
            '名前':{
                'value': extract(code,"","@")
            },
            'MAIL':{
                'value': code
            },
            '初期PASS':{
                'value': pass
            },
            'vision_累計': {
                'value': 0
            },
            'vision_月間': {
                'value': 0
            }
        }

    };
    let options_postrecords = {
        url: url,
        method: 'POST',
        headers: headers,
        'Content-Type': 'application/json',
        json: true,
        body:body
    };
    return options_postrecords;
}

//メンバー取得
function guest_get(headers,DOMAIN){
    let url = "https://" + DOMAIN + "/k/v1/records.json";
    let body = {"app": アプリid};
    let options_guestget = {
        url: url,
        method: 'GET',
        headers: headers,
        json: true,
        body: body
    };
    return options_guestget;
}

//メンバー更新
function guest_put(headers,DOMAIN,member){
    let url = "https://" + DOMAIN + "/k/guest/スペースID/v1/space/guests.json";
    let body = {"id": スペースid};
    body.guests = member;
    let options_guestput = {
        url: url,
        method: 'PUT',
        headers: headers,
        json: true,
        body: body
    };
    return options_guestput;
}

//メールアドレス抜き出し
function extract(str,before,after){
    const beforeIdx = str.indexOf(before);
    const afterIdx = str.lastIndexOf(after);
    let result;
    if (beforeIdx >= 0 && afterIdx >= 0) {
        result = str.substring(beforeIdx + before.length, afterIdx);
    }else if(!before && afterIdx >= 0){
        result = str.substring(0, afterIdx);
    }
    return result;
}

//パスワード生成
function pass_create(){
    let letters = 'abcdefghijklmnopqrstuvwxyz';
    let numbers = '0123456789';
    let string  = letters + letters.toUpperCase() + numbers;
    let len = 8;　　　//8文字
    let password=''; //文字列が空っぽという定義をする
    for (let i = 0; i < len; i++) {
        password += string.charAt(Math.floor(Math.random() * string.length));
    }
    password = password;
    return password;
}

//返信メッセージ作成
function remessage(code,pass){
    let result = "ご連絡ありがとうございます、下記の通りGuest ID を取得しました。" + 
    "\nURL: URL\nID(E-mail): " + code + "\nPassWord: " + pass;
    return result;
}
```
## 筆者の紹介
群馬県の渋川市・高崎市を中心に群馬県内でkintoneを利用したDX化支援を行っています。ご興味ある方はぜひご連絡ください。
https://ks-kiki.hp.peraichi.com/