昨天将产出的验证码写进了 Google Sheet,但我们还需要另一个功能:输入验证码找出所在Row,并且在同一列的其他 column 写入绑定的 userId 和 绑定时间。这样使用者在 Line Bot 输入验证码後,我们才能知道绑定这个验证码的使用者是谁。
因为产出的验证码放在 verification_code
的第一行,所以我们可以取出这一行每个储存格的值,再查找目标验证码的index,从而可以得知该验证码所在列号。
新增一个 tagVerificationCode.gs 内容如下:
function tagVerificationCode() {
var target = 'a55969eb';
// 连接到 verification_code sheet
var sheet = ReadMailAndInsertToGoogleSheet.connectToSheet('verification_code');
// 取得从 A1 开始到最後一列有资料的 AX 的所有值,X = getLastRow()
var columnValues = sheet.getRange(1, 1, sheet.getLastRow(), 1).getValues();
// 利用 findIndex 遍历 columnValues 查找 target 验证码,找到的话回传 index,否则回传 -1
var searchResult = columnValues.findIndex((element)=>element[0]==target);
Logger.log(searchResult);
}
将 target 的值改为想查找的验证码,然後执行看看结果:
然後进一步将 tagVerificationCode.gs 修改如下:
function tagVerificationCode(target, userId) {
var sheet = ReadMailAndInsertToGoogleSheet.connectToSheet('verification_code');
var columnValues = sheet.getRange(1, 1, sheet.getLastRow(), 1).getValues();
var searchResult = columnValues.findIndex((element)=>element[0]==target);
if (searchResult !== -1) {
searchResult++;
var targetRange = sheet.getRange(searchResult, 2, 1, 2);
targetRange.setValues([[userId, new Date()]]);
}
}
修改後记得储存,然後选取要执行的函式为 testTagVerificationCode
按下执行後查看结果:
试算表结果:
先前有提过,Google Sheet 虽然可以当成简易资料库使用,但其实是没有 Query & Insert 的概念的。而我们刚刚完成的 tagVerificationCode.gs 里用来查找某行资料有没有这个值,其实就有点类似 Query 的概念,所以很适合抽成共用 function 方便之後重复使用。
在 Read Mail
专案内新增 searchColumnValue.gs
function searchColumnValue(sheet, columnName, target) {
Logger.log('start to searchColumnValue');
// 先取得标题列的值
var headerRowValue = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
// 查看 columnName 在标题列的 index
var columnIndex = headerRowValue[0].indexOf(columnName);
if (columnIndex !== -1) {
columnIndex++;
// 抓出 columnName 那行所有的值
var columnValues = sheet.getRange(2, columnIndex, sheet.getLastRow(), 1).getValues();
// 回传查找结果
var searchResult = columnValues.findIndex((element)=>element[0]==target);
return searchResult;
}
}
因为已经部署过 Read Mail
了,有修改的话要管理部署 > 编辑 > 增加新版本
在 Reply Message
的资料库也要跟着切换版本,看看是否有正确读到最新版。有时候如果没有自动同步到最新开发人员版本,可以先切成别的版本再切回来就会正常。
加上标题列如下:
因为增加了标题列,所以 Reply Message
的 generateVerificationCode 跟 tagVerificationCode 也需要稍作修改,避免写入的范围有误差
修改 generateVerificationCode.gs 的 insertVerificationCode 如下:
function insertVerificationCode(uniqueVerificationCode) {
var sheet = ReadMailAndInsertToGoogleSheet.connectToSheet('verification_code');
var range = sheet.getRange(2, 1, uniqueVerificationCode.length, 1);
range.setValues(uniqueVerificationCode);
}
修改 tagVerificationCode.gs 如下:
function tagVerificationCode(target, userId) {
var sheet = ReadMailAndInsertToGoogleSheet.connectToSheet('verification_code');
var searchResult = ReadMailAndInsertToGoogleSheet.searchColumnValue(sheet, 'code', target);
if (searchResult !== -1) {
var targetRange = sheet.getRange((searchResult+2), 2, 1, 2);
targetRange.setValues([[userId, new Date()]]);
}
}
如此一来即可重复引用这个写好的查找功能~
Reply Message
加上身份验证接着让我们对 Reply Message
的流程稍作修改,加上简单的身份验证流程吧
Reply Message
收到 Message Event获取验证码
用来判断这个 userId 是否已经存在我们的绑定纪录里
function isUserIdVerified(userId) {
var sheet = ReadMailAndInsertToGoogleSheet.connectToSheet('verification_code');
var searchResult = ReadMailAndInsertToGoogleSheet.searchColumnValue(sheet, 'user_id', userId);
return (searchResult !== -1);
}
将 replyMessage.gs 修改以符合我们的新流程:
const CHANNEL_ACCESS_TOKEN = 'YOUR_CHANNEL_ACCESS_TOKEN';
function doPost(e) {
var requestContent = JSON.parse(e.postData.contents);
var event = requestContent.events[0];
// 必须是 Message Event
if (event && (event.type === 'message')) {
var replyToken = event.replyToken;
var userId = event.source && event.source.userId;
var userMessage = event.message.text;
var replyMessage = [];
if(isUserIdVerified(userId)) {
replyMessage = userIsVerifiedFlow(userMessage, userId);
} else {
replyMessage = userIsNotVerifiedFlow(userMessage, userId);
}
doReplyMessage(replyMessage, replyToken);
}
return ContentService.createTextOutput('success');
}
function userIsVerifiedFlow(userMessage, userId){
return (userMessage === '获取验证码') ? getValidationCodeMessage(userId) : getReplyMessage('无效的输入');
}
function userIsNotVerifiedFlow(userMessage, userId){
var bindResult = tagVerificationCode(userMessage, userId);
var replyMessage = bindResult ? '绑定成功!请点击选单或输入获取验证码。' : '请先进行身分认证绑定。'
return getReplyMessage(replyMessage);
}
function getValidationCodeMessage(userId) {
var validationCode = ReadMailAndInsertToGoogleSheet.app(userId);
return [{
'type': 'text',
'text': validationCode
}];
}
function getReplyMessage(message) {
return [{
'type': 'text',
'text': message
}];
}
function doReplyMessage(replyMessage, replyToken) {
var payload = {
replyToken: replyToken,
messages: replyMessage
};
UrlFetchApp.fetch('https://api.line.me/v2/bot/message/reply', {
'headers': {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN
},
'method': 'post',
'payload': JSON.stringify(payload)
});
}
tagVerificationCode 也要稍作修改,增加检查验证码是否已被绑定过(user_id 不为空),以符合我们的新流程:
function tagVerificationCode(target, userId) {
var sheet = ReadMailAndInsertToGoogleSheet.connectToSheet('verification_code');
var searchResult = ReadMailAndInsertToGoogleSheet.searchColumnValue(sheet, 'code', target);
if (searchResult !== -1) {
var targetRowIndex = searchResult+2;
var userIdValue = sheet.getRange(targetRowIndex, 2, 1, 1).getValue();
if (userIdValue.length === 0) {
var targetRange = sheet.getRange((searchResult+2), 2, 1, 2);
targetRange.setValues([[userId, new Date()]]);
return true;
}
}
return false;
}
修改完後一样要管理部署 > 编辑 > 建立新版本 如下:
接着把网页应用程序的网址复制,更新到验证码小帮手的 Messaging Api Webhook 网址
忘记怎麽设置的话请看 部署 Google App Script 专案(2) & Line Bot 简单回应讯息
设定好後就可以用验证码小帮手测试看看结果罗~
结果如下图:
Google Sheet 的结果如下:
以上~这样就完成了简单的身份验证流程。
当然还有很多可以完善的地方,例如虽然可以交由程序自动产生验证码跟绑定,但却要我们手动发送验证码给使用者,使用者也只能手动输入,实在是太不贴心~但这就是我们可以学习进步的地方!明天要做什麽还尚待决定~差不多也该进入 Liff 应用的篇幅了,那麽就待明天再揭晓主题吧~
>>: display : Inline、Block、Inline-Block
The lone wolf dies but the pack survives. ---- Ga...
嗨!大家好,昨天我们有提到,一开始两个区域有「目前没有新的任务」以及「尚未有任务完成」,这两个标题都...
FormActionTagHelper (窗体操作标记帮助程序) : 其非针对原生HTML任何TAG...
在学习Java继承的部分时,就想到进击巨人的设定,九大巨人的能力只要被其他人吃掉,能力就会被传承过去...
最近写一个ASP.NET WebForm的网页,允许使用者在TextBox输入各种文字,也包括Htm...