如何用LineBot進行線上測驗

老師們常常都要對學生做測驗,網路上已經有很多網頁式的線上測驗,但還沒見過有人做過在Line上使用的線上測驗。今天將上週所做的google表單問卷的Line程式稍微修改一下程式碼,就可以做出在Line上的線上測驗,感覺比較像有個人在對你一問一答,學生可能也不知道是個Line機器人在和他對答,似乎比較有趣些。

這個程式如果再稍加修改,還可以成為多人異地的搶答競賽,多人異地加入某個Line聊天室,由LineBot出題讓大家搶答,最後可以記錄出誰是得分王,對學生來說應該也是個滿刺激的活動。

1、在雲端硬碟建立一個試算表,檔名不拘,但是工作表必須是「歡迎詞」,並且輸入提示詞或是歡迎詞。

2、再新增一個叫做「問題」的工作表,線上測驗的問題及答案都輸入在這裡。

3、再新增一個工作表,名稱叫做「測驗結果」,每個人每題的測驗答案都會儲存在這個工作表。

4、將試算表網址列如下圖的這個部份的ID複製下來,接下來的程式需要用到它。

5、將舊有的index.js備份,並將以下內容重新輸入index.js

請注意,底下的程式碼請依據程式內的註釋,有六行要將之前取得的各種憑證放入修改:

//以下的四列require裡的內容,請確認是否已經用npm裝進node.js
var linebot = require('linebot');
var express = require('express');
var google = require('googleapis');
var googleAuth = require('google-auth-library');

//以下的引號內請輸入申請LineBot取得的各項資料,逗號及引號都不能刪掉
var bot = linebot({
  channelId: '請輸入LineBot的channelId',
  channelSecret: '請輸入LineBot的channelSecret',
  channelAccessToken: '請輸入LineBot的channelAccessToken'
});

//底下輸入client_secret.json檔案的內容
var myClientSecret=請將client_secret.json檔案的內容放在這裡,前後不能加引號

var auth = new googleAuth();
var oauth2Client = new auth.OAuth2(myClientSecret.installed.client_id,myClientSecret.installed.client_secret, myClientSecret.installed.redirect_uris[0]);

//底下輸入sheetsapi.json檔案的內容
oauth2Client.credentials =請將sheetsapi.json檔案的內容放在這裡,前後不能加引號

//試算表的ID,引號不能刪掉
var mySheetId='請輸入試算表的ID編號';

var title='';
var users=[];

var totalSteps=0;
var myQuestions=[];



//程式啟動後會去讀取試算表的歡迎詞工作表的內容
getTitle();
//程式啟動後會去讀取試算表的問題的工作表的內容
getQuestions();


//取得歡迎詞內容的函式
function getTitle() {
   var sheets = google.sheets('v4');
   sheets.spreadsheets.values.get({
      auth: oauth2Client,
      spreadsheetId: mySheetId,
      range:encodeURI('歡迎詞'),
   }, function(err, response) {
      if (err) {
         console.log('讀取問題檔的API產生問題:' + err);
         return;
      }
      title= response.values[0][0];
      console.log('title已下載完畢!');
   });
} 

//取得線上測驗問題的函式
function getQuestions() {
   var sheets = google.sheets('v4');
   sheets.spreadsheets.values.get({
      auth: oauth2Client,
      spreadsheetId: mySheetId,
      range:encodeURI('問題'),
   }, function(err, response) {
      if (err) {
         console.log('讀取問題檔的API產生問題:' + err);
         return;
      }
      var rows = response.values;
      if (rows.length == 0) {
         console.log('No data found.');
      } else {
         myQuestions=rows;
         totalSteps=myQuestions.length;
         console.log('要問的問題已下載完畢!');
      }
   });
}


//LineBot收到user的文字訊息時的處理函式
bot.on('message', function(event) {
   if (event.message.type === 'text') {
      var myId=event.source.userId;
      if (users[myId]==undefined){
         users[myId]=[];
         users[myId].userId=event.source.userId;
         users[myId].step=-1;
         users[myId].rightAns=0;
         users[myId].replies=[];
         users[myId].replies[0]='';
         users[myId].replies[1]=new Date();
         getDisplayName(event);
         sendMessage(event,title+'本次測驗共有'+totalSteps+'題:');
         setTimeout(function() {
            pushStepQuestion(users[myId].userId);
         }, 2000);
      }
      else{
         if(!isNaN(event.message.text)){
            checkAnswer(users[myId].userId,event.message.text);
         }else{
            sendMessage(event,'請用阿拉伯數字選擇答案!');
         }
      }
   }
});


//取得user的使用者名稱
function getDisplayName(eve){
   bot.getUserProfile(eve.source.userId);
   eve.source.profile().then(function (profile) {
      users[eve.source.userId].replies[0]=profile.displayName;
   }).catch(function (error) {
       // error 
   });
}


//這是將測驗結果儲存進試算表的函式
function appendMyRow(userId) {
   var request = {
      auth: oauth2Client,
      spreadsheetId: mySheetId,
      range:encodeURI('測驗結果'),
      insertDataOption: 'INSERT_ROWS',
      valueInputOption: 'RAW',
      resource: {
        "values": [
          users[userId].replies
        ]
      }
   };
   var sheets = google.sheets('v4');
   sheets.spreadsheets.values.append(request, function(err, response) {
      if (err) {
         console.log('The API returned an error: ' + err);
         return;
      }
   });
}


//檢查答案是否正確的函式
function checkAnswer(whoId,myAns){
   var myStep=users[whoId].step;
   if (myStep<totalSteps){
      users[whoId].answers=[];
      users[whoId].answers[myStep]=myAns;
      users[whoId].replies[myStep*2+2]=Number(myAns);
      if (myAns===myQuestions[myStep][6]){
         users[whoId].replies[myStep*2+3]=1;
         //以下一行為傳送貼圖程式,第一個參數是要傳送的對象,第二個為貼圖的package ID,第三個參數為貼圖ID
         sendSticker(whoId,1,13);
         users[whoId].rightAns++;
      }else{
         users[whoId].replies[myStep*2+3]=0;
         //以下一行為傳送貼圖程式,第一個參數是要傳送的對象,第二個為貼圖的package ID,第三個參數為貼圖ID
         sendSticker(whoId,1,3);
         bot.push(whoId,myQuestions[myStep][5]);
      }
      myStep++;
      if (myStep>=totalSteps){
         users[whoId].replies[myStep*2+2]=users[whoId].rightAns;
    appendMyRow(whoId);
         setTimeout(function() {
            bot.push(whoId,'測驗完畢!'+totalSteps+'題共答對'+users[whoId].rightAns+'題!');
            delete users[whoId];
         },700); 
      }else{
         setTimeout(function() {
            pushStepQuestion(whoId);
         }, 1000);
      }
   }
}

//送出貼圖的函式
function sendSticker(to,pkg_id,stk_id){
   var messageData = {
      type: 'sticker',
      packageId: pkg_id,
      stickerId: stk_id
   };
   bot.push(to,messageData);
}

//發問問題的函式
function pushStepQuestion(to){
   users[to].step++;
   var myStep=users[to].step;
   var myMsg='第'+(myStep+1)+'題:\n';
   myMsg+=(myQuestions[myStep][0]+'\n');
   for (var i=1;i<5;i++){ 
      myMsg+=('('+i+')'+myQuestions[myStep][i]+' ');
   }
   bot.push(to,myMsg);
}

//傳送訊息的函式
function sendMessage(eve,msg){
   eve.reply(msg).then(function(data) {
      // success 
      return true;
   }).catch(function(error) {
      // error 
      return false;
   });
}


const app = express();
const linebotParser = bot.parser();
app.post('/', linebotParser);

//因為 express 預設走 port 3000,而 heroku 上預設卻不是,要透過下列程式轉換
var server = app.listen(process.env.PORT || 8080, function() {
  var port = server.address().port;
  console.log("App now running on port", port);
});

以上的程式有使用到傳送貼圖的部份,LinbBot可以讓我們使用公用的貼圖,可以參考以下的文件選擇貼圖。

line貼圖編號.pdf

6、接下來要將修改過的index.js傳上heroku。指令如下:

  • d:
  • cd bottest (以上指令請依據你的資料夾位置做更改)
  • heroku login (這邊請依據提示輸入申請heroku時,所填的帳號及設定的密碼)
  • git add .
  • git commit -am 'ok'
  • git push heroku master

7、到heroku的網站,點選More→View logs,如果看到如下的訊息,則表示程式已正常啟動。

8、接下來就可以用Line進行線上測驗了

9、測驗結果會即時儲存在試算表的「測驗結果」工作表中