Skip to content

Commit

Permalink
feat: merge anti spam feature (#1)
Browse files Browse the repository at this point in the history
* feat: try to merge anti spam

* feat: router of sign up

* feat: check spam
  • Loading branch information
wiidede committed Nov 25, 2023
1 parent bd78565 commit 9738ecb
Show file tree
Hide file tree
Showing 13 changed files with 388 additions and 86 deletions.
17 changes: 17 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/server.js"
}
]
}
24 changes: 16 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,25 @@

<img width="700" src="https://cdn.jun6.net/201806062257_798.png" />

### 必选参数

* `SITE_NAME` : 网站名称。
* `SITE_URL` : 网站地址, **最后不要加 `/`**
* `SMTP_USER` : SMTP 服务用户名,一般为邮箱地址。
* `SMTP_PASS` : SMTP 密码,一般为授权码,而不是邮箱的登陆密码,请自行查询对应邮件服务商的获取方式
* `SMTP_SERVICE` : 邮件服务提供商,支持 `QQ``163``126``Gmail``"Yahoo"``......` ,全部支持请参考 : [Nodemailer Supported services](https://nodemailer.com/smtp/well-known/#supported-services)。 --- *如这里没有你使用的邮件提供商,请查看[自定义邮件服务器](/高级配置.md#自定义邮件服务器)*
* `SENDER_NAME` : 寄件人名称。
### 详情

变量 | 示例 | 说明
--- | ------ | ---------
SITE_NAME | Deserts | [必填]博客名称
SITE_URL | https://panjunwen.com | [必填]首页地址
**SMTP_SERVICE** | QQ | [新版支持]邮件服务提供商,支持 QQ、163、126、Gmail 以及 [更多](https://nodemailer.com/smtp/well-known/#supported-services)
SMTP_USER | xxxxxx@qq.com | [必填]SMTP登录用户
SMTP_PASS | ccxxxxxxxxch | [必填]SMTP登录密码(QQ邮箱需要获取独立密码)
SENDER_NAME | Deserts | [必填]发件人
SENDER_EMAIL | xxxxxx@qq.com | [必填]发件邮箱
ADMIN_URL | https://xxx.leanapp.cn/ | [建议]Web主机二级域名(云引擎域名),用于自动唤醒
BLOGGER_EMAIL | xxxxx@gmail.com | [可选]博主通知收件地址,默认使用SENDER_EMAIL
AKISMET_KEY | xxxxxxxx | [可选]Akismet Key 用于垃圾评论检测,设为MANUAL_REVIEW开启人工审核,留空不使用反垃圾

## 高级配置

[垃圾评论检测](/高级配置.md#垃圾评论检测)

[自定义邮件模板](/高级配置.md#自定义邮件模板)

[自定义收件邮箱](/高级配置.md#自定义收件邮箱)
Expand Down
1 change: 1 addition & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ app.get('/', (req, res) => {

// 可以将一类的路由单独保存在一个文件中
app.use('/comments', require('./routes/comments'))
app.use('/sign-up', require('./routes/sign-up'))

// 处理登录请求(可能来自登录界面中的表单)
app.post('/login', (req, res) => {
Expand Down
8 changes: 6 additions & 2 deletions cloud.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ const process = require('node:process')
const AV = require('leanengine')
const request = require('request')
const mail = require('./utilities/send-mail')
const spam = require('./utilities/check-spam')

const Comment = AV.Object.extend('Comment')

function formatComment(comment) {
return `评论(${comment.get('objectId')}) by ${comment.get('nick')} - 【${comment.get('comment')}】`
}

async function sendMailByComment(comment) {
async function sendMailByComment(comment, defaultIp) {
const ip = comment.get('ip') || defaultIp
spam.checkSpam(comment, ip)

const taskList = []
let err = false
const isNotified = comment.get('isNotified')
Expand Down Expand Up @@ -52,7 +56,7 @@ async function sendMailByComment(comment) {
AV.Cloud.afterSave('Comment', async (request) => {
const currentComment = request.object
console.log('hook(after save comment - 收到一条评论): ', formatComment(currentComment))
await sendMailByComment(currentComment)
await sendMailByComment(currentComment, request.meta.remoteAddress)
return 'finish'
})

Expand Down
34 changes: 22 additions & 12 deletions public/stylesheets/style.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
body {
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Droid Sans, Helvetica Neue, sans-serif;
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,sans-serif;
font-size: 1rem;
}

Expand Down Expand Up @@ -29,29 +29,29 @@ li {
padding: 0;
}


.header {
.header{
display: flex;
-ms-flex-direction: row;
flex-direction: row;
align-items: flex-start;
align-items: center;
justify-content: space-between;
}

.header .title {
flex: 90%;
@media screen and (max-width:768px) {
.comment-main {
padding: 1rem;
}
}

.logout-wrapper {}

.comment-main {
.comment-main{
padding: 1rem 5rem;
}

.vhead {
padding-bottom: 0.5rem;
}

.vhead a {
.vhead a , .vhead #nick {
font-weight: bolder;
color: #333;
}
Expand All @@ -70,6 +70,7 @@ li {

.vcomment {
line-height: 1.8;
word-wrap: break-word;
}

.vcard {
Expand All @@ -94,12 +95,16 @@ li {
margin-top: 4rem;
}

.gh-signup {
width: 600px !important;
}

.gh-signin {
display: flex;
-ms-flex-direction: column;
flex-direction: column;
padding: 1rem 2rem;
width: 350px;
width: 320px;
border: 1px solid #dae1e3;
background: #f8fbfd;
border-radius: 5px;
Expand All @@ -117,7 +122,7 @@ li {

.sign-in-wrap input {
padding: 10px;
margin: 1rem 1rem;
margin: 1rem 0;
border: 1px solid #dae1e3;
font-size: 1rem;
line-height: 1.5em;
Expand Down Expand Up @@ -148,3 +153,8 @@ li {
.red {
color: #ee1000;
}

.blue{
padding-left: 9px;
color: #33b1ff;
}
53 changes: 48 additions & 5 deletions routes/comments.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
const process = require('node:process')
const router = require('express').Router()
const AV = require('leanengine')
const mail = require('../utilities/send-mail')
const spam = require('../utilities/check-spam')

const Comment = AV.Object.extend('Comment')

Expand All @@ -14,14 +16,12 @@ router.get('/', (req, res, next) => {
query.find().then((results) => {
res.render('comments', {
title: `${process.env.SITE_NAME}上的评论`,
domain: process.env.SITE_URL,
comment_list: results,
})
}, (err) => {
if (err.code === 101) {
res.render('comments', {
title: `${process.env.SITE_NAME}上的评论`,
domain: process.env.SITE_URL,
comment_list: [],
})
}
Expand All @@ -35,15 +35,58 @@ router.get('/', (req, res, next) => {
}
})

router.get('/resend-email', (req, res, next) => {
if (req.currentUser) {
const query = new AV.Query(Comment)
query.get(req.query.id).then((object) => {
query.get(object.get('rid')).then((parent) => {
mail.send(object, parent)
res.redirect('/comments')
}).catch(next)
}).catch(next)
}
else {
res.redirect('/')
}
})

router.get('/delete', (req, res, next) => {
if (req.currentUser) {
const query = new AV.Query(Comment)
query.get(req.query.id).then((object) => {
object.destroy()
res.redirect('/comments')
}, (err) => {
if (err)
console.error(err)
}).catch(next)
}
else {
res.redirect('/')
}
})

router.get('/not-spam', (req, res, next) => {
if (req.currentUser) {
const query = new AV.Query(Comment)
query.get(req.query.id).then((object) => {
object.set('isSpam', false)
object.set('ACL', { '*': { read: true } })
object.save()
spam.submitHam(object)
res.redirect('/comments')
}).catch(next)
}
else {
res.redirect('/')
}
})
router.get('/mark-spam', (req, res, next) => {
if (req.currentUser) {
const query = new AV.Query(Comment)
query.get(req.query.id).then((object) => {
object.set('isSpam', true)
object.set('ACL', { '*': { read: false } })
object.save()
spam.submitSpam(object)
res.redirect('/comments')
}).catch(next)
}
else {
Expand Down
50 changes: 50 additions & 0 deletions routes/sign-up.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
'use strict'
const process = require('node:process')
const router = require('express').Router()
const AV = require('leanengine')

const User = AV.Object.extend('_User')

// Comment 列表
router.get('/', (req, res) => {
if (req.currentUser) {
res.redirect('/comments')
}
else {
const adminMail = process.env.BLOGGER_EMAIL || process.env.SMTP_USER
const q = new AV.Query(User)
q.equalTo('email', adminMail)
q.find().then((results) => {
if (results.length > 0) {
res.redirect('/')
}
else {
res.render('sign-up', {
email: adminMail,
})
}
})
}
})

router.post('/', (req, res) => {
const adminMail = process.env.BLOGGER_EMAIL || process.env.SMTP_USER
const q = new AV.Query(User)
q.equalTo('email', adminMail)
q.find().then((results) => {
if (results.length > 0) {
res.redirect('/')
}
else {
const user = new AV.User()
user.setUsername(req.body.username)
user.setPassword(req.body.password)
user.setEmail(req.body.email)
user.signUp().then(() => {
})
res.redirect('/')
}
})
})

module.exports = router
Loading

0 comments on commit 9738ecb

Please sign in to comment.