Learning Objectives
- 把 webhook、資料庫、卡片拆成不同檔案,讓程式維持好改
- 用圖文選單、Flex Message 與 postback 做出報名流程,不必讓使用者打字
- 用 SQLite 記住報名資料,並處理重複報名、額滿與取消
- 做一個會推送的管理員路由,並說明它為什麼要自己驗證身分
- 替機器人補上缺的功能,並測試不同使用者看到的結果
這個專題要做什麼
前面每一課都只處理一個觀念。真的機器人要把它們接起來:使用者加好友、從選單看到場次、按一下就報名、之後可以取消,負責的人還能通知報名的同學。這一課就做這個機器人,名字叫「讀書會小幫手」。
| 功能 | 用到 | 哪一課學過 |
|---|---|---|
| 加好友時傳歡迎訊息 | FollowEvent |
第 4 課 |
| 選單放在聊天室下方 | Rich Menu | 第 7 課 |
| 用卡片列出場次 | Flex Message、carousel | 第 8 課 |
| 按按鈕報名,使用者不必打字 | PostbackAction、parse_qs |
第 7 課 |
| 記住誰報名了哪一場 | SQLite、user_id |
第 9 課 |
| 通知報名的人 | multicast、額度 |
第 6 課 |
| 用語音問(選做) | get_message_content、Whisper |
第 11 課 |
程式超過一個畫面就不好找,所以拆成三個檔案:
| 檔案 | 負責 | 不做 |
|---|---|---|
app.py |
webhook、判斷是哪種事件、決定回什麼 | 不寫 SQL,也不組卡片的 JSON |
db.py |
所有 SQL | 不知道 LINE 的存在 |
flex.py |
把查到的資料組成 Flex Message | 不查資料庫 |
db.py 用的是後端開發軌第 9 課的 get_db() 寫法;SQL 不熟可以看 SQL 軌。資料表只有兩張:sessions 是場次,signups 記誰報名了哪一場,一人一場一列。
逐步看:資料變成卡片
場次是資料,卡片是由迴圈產生的,所以新增場次不必改卡片程式。按播放,注意 on_text 裡的迴圈每跑一次,cards 多一張;每張卡片的按鈕都帶著自己的 id。
逐步看:報名寫進資料庫
同一個人按兩次會發生什麼?這裡不是先查再寫,而是讓資料庫的 UNIQUE 擋下第二筆。看 try 和 except 各走了哪一次。
誰都能呼叫的路由要自己驗證
/callback 有簽章驗證,只有 LINE 平台算得出正確的簽章。發公告的 /announce 是你自己開的路由,LINE 不會經過它,也沒有任何東西替它驗證。網址一旦公開,任何人都能 POST,而且它會用你的官方帳號傳訊息給使用者,額度也算你的。
這一課用一把金鑰(ADMIN_KEY,放環境變數)示範最簡單的做法,比對用 hmac.compare_digest。實際的網站通常是管理員登入後才看得到發公告的頁面,做法見後端開發軌第 15、16 課。
用 multicast 而不是 broadcast,是因為公告只和報名這一場的人有關。額度的計算方式是收件人數:一則訊息傳給兩個人算兩則,封鎖的人不計入;reply 完全不計入。實際的額度與價格依方案與地區而不同,請看官方說明。
逐步看:驗證金鑰、推送、額度
發三次公告:第一次金鑰是猜的,第二次傳給兩個人,第三次其中一人已經封鎖。看 quota_used 怎麼變。
動手做:候補遞補
報名額滿的人會排進候補。有人取消時,要把候補最前面的人轉成正取,並主動通知他。取消的人用 reply 回覆,遞補的人要用 push:他沒有傳任何訊息,手上沒有可以用的 reply token。
完成 promote_next()。資料表 waitlist 的 id 越小排越前面。
想一想
資料表已經有 UNIQUE (user_id, session_id),這個限制主要解決什麼問題?
/callback 驗證了簽章。為什麼 /announce 還要自己檢查金鑰?
下面這段程式會印出什麼?
from urllib.parse import parse_qs
params = parse_qs('action=join&id=3')
print(params['id'])
一則公告用 multicast 傳給 30 個 userId,其中 2 人封鎖了機器人。依官方的計算方式,這次計入額度多少則?
遞補的同學要收到通知,為什麼不能用 reply_message?
重點整理
- 程式拆成 webhook、資料庫、卡片三塊,每個檔案只管一件事
- 圖文選單、Flex 按鈕、postback 讓使用者不必打字,
data由你設計 - 重複與額滿這類規則,要在伺服器和資料庫判斷,不能只靠畫面
- 換一個使用者試試看:每個人的狀態以
user_id分開 - 自己開的路由沒有 LINE 的簽章保護,要自己驗證身分
- 推送要想清楚:該通知誰、算幾則、對方想不想收
接下來可以加的功能
| 方向 | 要處理的事 |
|---|---|
| 開場前一天自動提醒 | 排程工作(cron);時間要以使用者所在時區思考 |
| 建立場次的管理頁面 | 登入、權限,見後端開發軌 |
| 用語言模型回答課程問題 | 第 10 課的逾時、成本與標示;模型可能答錯 |
| 同時報名的競爭 | 兩人同時按最後一個名額時,先算人數再寫入可能超收,要用交易處理 |
| 使用者刪除自己的資料 | 提供「刪除我的資料」功能,並寫在隱私說明裡 |
下一課離開模擬環境:申請官方帳號,把機器人接上真的 LINE。