Valine Admin 配置教學 - 設定 Valine 作為評論區/留言版並透過 Email 取得留言通知

螢幕擷取畫面 2022-05-05 004055

前言

簡單來說,這篇是繼去年 3 月的時候寫的一篇在 Jekyll 上使用 Valine 作為評論系統/留言版的文章的後續優化。

其實自本站採用 Valine 作為留言系統後,一直感覺都沒有什麼問題,加上留言的讀者也不多,所以時隔一年我都遲遲沒有對留言系統進行優化。直到有一次我無言間發現了某個文章有人留言,但我沒有及時的回覆,加上我回覆後對方也不一定知道,因此我發現 email 留言通知功能十分重要。

事前準備 - 在 Email 上生成 App 專用密碼

這裡介紹 2 個常用的郵箱,分別是 Gmail 和 iCloud 的做法

Gmail

Google 的 App 專用密碼生成網址 : https://myaccount.google.com/apppasswords

2022-05-03 10_14_12-應用程式密碼 — Mozilla Firefox

選取應用程式選取裝置都可以任意選,只是方便自己記憶這個密碼是用來作什麼用途。

2022-05-02 17_26_30-應用程式密碼 — Mozilla Firefox

iCloud

Apple 的 App 專用密碼生成網址 : https://appleid.apple.com/

登入自己的 Apple ID :

2022-05-03 10_09_39-管理您的 Apple ID — Mozilla Firefox

2022-05-02 23_48_14-管理您的 Apple ID — Mozilla Firefox

如同一 Apple ID 下有多個郵件(例如自訂網域),經過試驗後,SMTP_USER 一欄需填寫 XXX@icloud.com 這信箱名稱。

Valine 留言透過 Email 提醒

1.配置 LeanCloud 雲引擎變數

LeanCloud 官網: https://console.leancloud.app

1.點選雲引擎 -> Web -> 設置,先創建雲引擎域名,用於管理員後台管理信息。

圖片

2.點選雲引擎 -> Web -> 設置,添加新變量,填寫的方式以下這樣。

SMTP_PASS 一欄填入之前生成的 APP 專用密碼,格式是 wnxxxxxxxxxxxxkv,全小寫不用 - 符號。

2022-05-03 16_15_44-设置 · web · 云引擎 · Valine — Mozilla Firefox

變量 例子 說明
SITE_NAME AnkMak Blog [必須] 網站名稱
SITE_URL https://ankmak.com [必須] 網站 URL
SMTP_SERVICE iCloud [必須] SMTP 服務(支援列表)
SMTP_USER xxx@icloud.com [必須] iCloud 郵箱名稱
SMTP_PASS wnxxxxxxxxxxxxkv [必須] 剛才產生的 App 密碼
SENDER_NAME Ank Mak [必須] 寄件人名稱
SENDER_EMAIL xxx@xxx.xx [必須] 寄件人 Email (這裡可填 iCloud 的自訂域名郵箱,實測有效)
ADMIN_URL https://xxx-xxx.avosapps.us [建議] 自動喚醒服務用(填入剛才創建的雲引擎域名)
BLOGGER_EMAIL xxx@xxx.xx [可選] 收件 email,默認為 SENDER_EMAIL
AKISMET_KEY xxxxxxxx [可選] Akismet Key 用於垃圾評論檢測,設為 MANUAL_REVIEW 表示開啟人工審核,留空為不使用

更多變量的說明參見 Github 上 Valine-Admin 文檔: https://github.com/DesertsP/Valine-Admin

2.部署 LeanCloud 雲引擎

2022-05-03 16_55_20-部署 · web · 云引擎 · Valine — Mozilla Firefox

Git 網址填入 https://github.com/DesertsP/Valine-Admin.git 即可一鍵部署。

圖片

這時候便可以測試一下留言,理論上已經可以收到郵箱通知

評論管理

設置管理員用於管理信息,註冊網址為 https://雲引擎域名.avosapps.us/sign-up (可以在部署狀態裡找到)

2022-05-03 17_08_15-螢幕擷取畫面 2022-05-02 180735 png - 相片

有了管理員之後,查看和管理評論就很方便了~

2022-05-03 17_09_39-AnkMak Blog上的评论 — Mozilla Firefox

定時自動喚醒

由於根據官方說法,免費版的雲引擎每天最多運行 18 個小時,而且每半個小時會執行休眠策略,在休眠期間會暫停郵件通知服務,所以我們需要啟動 2 項雲函數定時任務來解決休眠時的問題:

  • 自動喚醒 : 每半小時執行一次喚醒以防止休眠(先要創建雲引擎域名)
  • 漏發郵件檢查 : 每天的固定時間檢查過去 24 小時內漏發的郵件並重發

2022-05-03 22_38_32-定时任务 · 云引擎 · Valine — Mozilla Firefox

以下是我對雲函數的設定:

選擇 self-wake 雲函數,Cron 表達式為 0 */30 0-17 * * ?,表示每天 00:00 到 17:59 ,每隔 30 分鐘訪問雲引擎。(由於國際版使用 UTC-0 時間,即每天早上 8 點到 凌晨 01:59,所以最後一次執行為 01:30)

選擇 resend-mails 雲函數,Cron 表達式為 0 0 0-16 * * ?,表示每天 00:00 到 16:59 內,每小時一次檢查過去 24 小時內漏發的通知郵件並補發。

時間上可以按照自己的方式設定

LeanCloud 流控問題的解決方法

“error”:”因流控原因,通过定时任务唤醒体验版实例失败,建议升级至标准版云引擎实例避免休眠 https://url.leanapp.cn/dwAEksv”

由於官方有流量控制的問題,所以 LeanCloud 內建的定時任務只適用於當天,隔天早上起床後就會在日誌裡出現定時任務喚醒體驗版實例失敗的訊息:

螢幕擷取畫面 2022-05-06 132454

方法一:

也最簡單的解決方法,就是登入雲引擎的後台,也就是評論管理系統!

注意不是登入 blog 也不是 LeanCloud,是雲引擎域名(https://xxx.avosapps.us)

只要當天登入過一次評論管理系統,定時任務裡的自動喚醒又會正常運作,但流控問題隔天又會發生。

所以這種方法就需要每天早上手動的登錄雲引擎的後台,用來激活容器。

方法二:

透過外部訪問用來激活容器(實測有效)

在自己的 VPS 上建立 python 腳本

# -*- coding: utf8 -*-
import urllib.request
url="your URL"
req=urllib.request.Request(url)
urllib.request.urlopen(req)
print("外部訪問運行完成!")

記得把 your URL 換成雲引擎的 url

sudo crontab -e 加到定時排程:

*/20 8-23 * * * python /home/user/wake_up.py

由於外部訪問並沒有流控問題,因此我干脆設定得頻繁一點,在早上 08:00 到晚上 23:00,每 20 分鐘喚醒一次,不過依然要遵守免費版實例只能運行 18 小時的規則,所以我在設定上預留了一些額外時間。

參考自解夏 - Blog 之 Valine Admin(二)LeanCloud 唤醒服务

其他更多的方法:

如想知道更多的解決辦法,可參考 小康博客 - 优雅解决 LeanCloud 流控问题

必填欄位設定

由於新增了郵件的通知功能,如果留言時不提供郵箱的話就沒用了,因此我把 NickName 和 Email 都設定為必要選項。

到目錄: jekyll-TeXt-theme-tech/_includes/comments-providers/valine.html (每個人的目錄位置可能不同)

在括號行內加入 requiredFields: ['nick','mail'],

var _config = {
  el: '#vcomments',
  appId:  '',
  appKey: '',
  serverURLs: 'https://xxxxxxxx.api.lncldglobal.com',
  verify: true,
  requiredFields: ['nick','mail'],
};

自定義語言設定

由於把 NickName 和 Email 都設定為必填項,於是我就想更改一下這裡的占位符:

2022-05-03 22_50_20-部落格搬遷 - 記錄從零開始的架站步驟(更換域名、更換 VPS、更換 Arch Linux server) - Ank's Blog — Mozilla Fir

剛以為屬於配置項裡,類似於 placeholder 這種占位符可以簡單的自行設定,但原來是屬於系統語言的一部分,找到官方的教學,發現能改的地方可以有很多。

// 1.定義 langName 和 langMode 
var langName = 'en',
    langMode = {	
        "nick": "NickName",
        "mail": "E-Mail",
        "link": "Website(http://)",
        "nickFail":"NickName cannot be less than 3 bytes.",
        "mailFail":"Please confirm your email address.",
        "sofa": "No comment yet.",
        "submit": "Submit",
        "reply": "Reply",
        "cancelReply": "Cancel reply",
        "comments": "Comments",
        "cancel": "Cancel",
        "confirm": "Confirm",
        "continue": "Continue",
        "more": "Load More...",
        "preview": "Preview",
        "emoji": "Emoji",
        "expand": "See more....",
        "seconds": "seconds ago",
        "minutes": "minutes ago",
        "hours": "hours ago",
        "days": "days ago",
        "now": "just now",
        "uploading":"Uploading ...",
        "uploadDone":"Upload completed!",
        "busy":"Submit is busy, please wait...",
        "code-98":"Valine initialization failed, please check your version of av-min.js.",
        "code-99": "Valine initialization failed, Please check the `el` element in the init method.",
        "code-100": "Valine initialization failed, Please check your appId and appKey.",
        "code-140":"The total number of API calls today has exceeded the development version limit.",
        "code-401": "Unauthorized operation, Please check your appId and appKey.",
        "code-403": "Access denied by API domain white list, Please check your security domain."
    };

// 2.初始化 Valine
new Valine({
    el:'#vcomment',
    appId:'Your appId',
    appKey:'Your appKey',
    lang: langName,
    langMode: langMode
})

而我還要稍微在這裡設置一下(TeXt 主題所需)

%- if _page_lang_slice != 'zh'  -%
  _config.lang = langMode;
%- endif -%

頭像設定

自己的頭像

Valine 目前是使用 Gravatar 作為留言板的頭像

Gravatar(https://en.gravatar.com) 官網註冊一個帳號並設定頭像,請確定自己註冊時所使用的郵箱,評論時填寫一樣的郵箱便會顯示頭像。

2022-05-03 23_02_49-Gravatar - Globally Recognized Avatars — Mozilla Firefox

其他用戶的頭像

沒有自定義的郵箱,有以下 7 種默認值可選:

參數值 頭像 說明
空字符串'' 圖片 Gravatar 官方圖形
mp 圖片 神秘人(一個灰白頭像)
identicon 圖片圖片 抽象幾何圖形(根據郵箱生成)
monsterid 圖片圖片 小怪物(根據郵箱生成)
wavatar 圖片圖片 用不同面孔和背景組合生成的頭像(根據郵箱生成)
retro 圖片圖片 八位像素復古頭像(根據郵箱生成)
robohash 圖片 一種具有不同顏色、面部等的機器人(根據郵箱生成)
hide   不顯示頭像

根據個人喜好選擇,這裡我自己選擇了 monsterid 小怪物作為其他用戶的頭像。

到目錄: jekyll-TeXt-theme-tech/_includes/comments-providers/valine.html (每個人的目錄位置可能不同)

在括號行內加入 avatar: 'monsterid',

var _config = {
  el: '#vcomments',
  appId:  '',
  appKey: '',
  serverURLs: 'https://xxxxxxxx.api.lncldglobal.com',
  verify: true,
  requiredFields: ['nick','mail'],
  avatar: 'monsterid',
};

效果如下:

圖片

垃圾評論檢測

Akismet (Automattic Kismet)是應用廣泛的一個垃圾留言過濾系統,其作者是大名鼎鼎的WordPress 創始人 Matt Mullenweg,Akismet也是WordPress默認安裝的插件,其使用非常廣泛,設計目標便是幫助博客網站來過濾留言Spam。有了Akismet之後,基本上不用擔心垃圾留言的煩惱了。啟用Akismet後,當博客再收到留言會自動將其提交到Akismet並與Akismet上的黑名單進行比對,如果名列該黑名單中,則該條留言會被標記為垃圾評論且不會發布。

2022-05-04 00_09_33-My Akismet Account — Mozilla Firefox

  1. 先到 akismet 官網(https://akismet.com/development/)註冊一個帳號,這裡我選擇用 Gravatar 的帳號登入
  2. 選擇 Developers Plan
  3. 取得 AKISMET API KEY
  4. AKISMET API KEY 填入到 leancloudAKISMET_KEY 參數裡
  5. 重啟部署

郵件通知模板

變量 範本 說明
MAIL_SUBJECT ${PARENT_NICK},您在 ${SITE_NAME} 上的評論收到了回覆 [可選] @回覆時郵件標題
MAIL_TEMPLATE 見下文 [可選] @回覆時郵件內容
MAIL_SUBJECT_ADMIN ${SITE_NAME} 上有新評論了 [可選] 博主通知時的郵件標題
MAIL_TEMPLATE_ADMIN 見下文 [可選] 博主通知時郵件內容

郵件通知分成了兩種:

  1. 通知博主
  2. 被@通知

1.通知博主 的默認範本

<div style="border-top:2px solid #12ADDB;box-shadow:0 1px 3px #AAAAAA;line-height:180%;padding:0 15px 12px;margin:50px auto;font-size:12px;"><h2 style="border-bottom:1px solid #DDD;font-size:14px;font-weight:normal;padding:13px 0 10px 8px;">您在<a style="text-decoration:none;color: #12ADDB;" href="${SITE_URL}" target="_blank">${SITE_NAME}</a>上的文章有了新的评论</h2><p><strong>${NICK}</strong>回复说:</p><div style="background-color: #f5f5f5;padding: 10px 15px;margin:18px 0;word-wrap:break-word;"> ${COMMENT}</div><p>您可以点击<a style="text-decoration:none; color:#12addb" href="${POST_URL}" target="_blank">查看回复的完整內容</a><br></p></div></div>

2. 被@通知 的默認範本

<div style="border-top:2px solid #12ADDB;box-shadow:0 1px 3px #AAAAAA;line-height:180%;padding:0 15px 12px;margin:50px auto;font-size:12px;"><h2 style="border-bottom:1px solid #DDD;font-size:14px;font-weight:normal;padding:13px 0 10px 8px;">您在<a style="text-decoration:none;color: #12ADDB;" href="${SITE_URL}" target="_blank">            ${SITE_NAME}</a>上的评论有了新的回复</h2> ${PARENT_NICK} 同学,您曾发表评论:<div style="padding:0 12px 0 12px;margin-top:18px"><div style="background-color: #f5f5f5;padding: 10px 15px;margin:18px 0;word-wrap:break-word;">            ${PARENT_COMMENT}</div><p><strong>${NICK}</strong>回复说:</p><div style="background-color: #f5f5f5;padding: 10px 15px;margin:18px 0;word-wrap:break-word;"> ${COMMENT}</div><p>您可以点击<a style="text-decoration:none; color:#12addb" href="${POST_URL}" target="_blank">查看回复的完整內容</a>,欢迎再次光临<a style="text-decoration:none; color:#12addb" href="${SITE_URL}" target="_blank">${SITE_NAME}</a><br></p></div></div>

(另外) 被@通知 的彩紅範本

<div style="border-radius: 10px 10px 10px 10px;font-size:13px;    color: #555555;width: 666px;font-family:'Century Gothic','Trebuchet MS','Hiragino Sans GB',微软雅黑,'Microsoft Yahei',Tahoma,Helvetica,Arial,'SimSun',sans-serif;margin:50px auto;border:1px solid #eee;max-width:100%;background: #ffffff repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 1px 5px rgba(0, 0, 0, 0.15);"><div style="width:100%;background:#49BDAD;color:#ffffff;border-radius: 10px 10px 0 0;background-image: -moz-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));background-image: -webkit-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));height: 66px;"><p style="font-size:15px;word-break:break-all;padding: 23px 32px;margin:0;background-color: hsla(0,0%,100%,.4);border-radius: 10px 10px 0 0;">您在<a style="text-decoration:none;color: #ffffff;" href="${SITE_URL}"> ${SITE_NAME}</a>上的留言有新回复啦!</p></div><div style="margin:40px auto;width:90%"><p>${PARENT_NICK} 同学,您曾在文章上发表评论:</p><div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:14px;color:#555555;">${PARENT_COMMENT}</div><p>${NICK} 给您的回复如下:</p><div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:14px;color:#555555;">${COMMENT}</div><p>您可以点击<a style="text-decoration:none; color:#12addb" href="${POST_URL}#comments">查看回复的完整內容</a>,欢迎再次光临<a style="text-decoration:none; color:#12addb"                href="${SITE_URL}"> ${SITE_NAME}</a></p><style type="text/css">a:link{text-decoration:none}a:visited{text-decoration:none}a:hover{text-decoration:none}a:active{text-decoration:none}</style></div></div>

注意,下列變數僅用於郵件範本裡的 HTML 變數中,請勿與雲引擎環境變數混淆

範本裡的變數 說明
SITE_NAME 網站名稱
SITE_URL 網站 URL
POST_URL 文章 URL (完整路徑)
PARENT_NICK 收件人名稱 (被@者、父級評論人)
PARENT_COMMENT 父級評論內容
NICK 新評論者名稱
COMMENT 新評論內容

透過以上這些變數,如果自己會 HTML 語法,完全可以自己弄一個全新的通知郵件樣式,而我自己就改了一少部分,順便把簡體字全換成了繁體字。

自己收到留言時的效果如下:

2022-05-05 00_33_54-IMG_9787 png - 相片

別人收到回覆時的效果如下:

圖片

donate