forked from HCLonely/Valine-Admin
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
35 changed files
with
860 additions
and
4,677 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ npm-debug.log | |
start.sh | ||
.avoscloud | ||
.leancloud | ||
.history | ||
|
||
# VIM | ||
*~ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,126 +1,131 @@ | ||
'use strict'; | ||
'use strict' | ||
|
||
var express = require('express'); | ||
var timeout = require('connect-timeout'); | ||
var path = require('path'); | ||
var cookieParser = require('cookie-parser'); | ||
var bodyParser = require('body-parser'); | ||
var AV = require('leanengine'); | ||
var express = require('express') | ||
var timeout = require('connect-timeout') | ||
var path = require('path') | ||
var cookieParser = require('cookie-parser') | ||
var bodyParser = require('body-parser') | ||
var AV = require('leanengine') | ||
|
||
// 加载云函数定义,你可以将云函数拆分到多个文件方便管理,但需要在主文件中加载它们 | ||
require('./cloud'); | ||
require('./cloud') | ||
|
||
var app = express(); | ||
var app = express() | ||
|
||
// 设置模板引擎 | ||
app.set('views', path.join(__dirname, 'views')); | ||
app.set('view engine', 'ejs'); | ||
app.set('views', path.join(__dirname, 'views')) | ||
app.set('view engine', 'ejs') | ||
|
||
app.use(express.static('public')); | ||
app.use(express.static('public')) | ||
|
||
// 设置默认超时时间 | ||
app.use(timeout('15s')); | ||
app.use(timeout('15s')) | ||
|
||
// 加载云引擎中间件 | ||
app.use(AV.express()); | ||
app.use(AV.express()) | ||
|
||
app.enable('trust proxy'); | ||
app.enable('trust proxy') | ||
// 需要重定向到 HTTPS 可去除下一行的注释。 | ||
app.use(AV.Cloud.HttpsRedirect()); | ||
|
||
app.use(bodyParser.json()); | ||
app.use(bodyParser.urlencoded({ extended: false })); | ||
app.use(cookieParser()); | ||
app.use(AV.Cloud.CookieSession({ secret: 'my secret', maxAge: 3600000, fetchUser: true })); | ||
|
||
app.get('/', function(req, res) { | ||
if (req.currentUser) { | ||
res.redirect('/comments'); | ||
} else { | ||
res.render('index'); | ||
} | ||
}); | ||
app.use(AV.Cloud.HttpsRedirect()) | ||
|
||
app.use(bodyParser.json()) | ||
app.use(bodyParser.urlencoded({ extended: false })) | ||
app.use(cookieParser()) | ||
app.use(AV.Cloud.CookieSession({ secret: 'my secret', maxAge: 3600000, fetchUser: true })) | ||
|
||
app.get('/', function (req, res) { | ||
console.log('访问评论后台') | ||
if (req.currentUser) { | ||
res.redirect('/comments') | ||
} else { | ||
res.render('index') | ||
} | ||
}) | ||
|
||
// 可以将一类的路由单独保存在一个文件中 | ||
app.use('/comments', require('./routes/comments')); | ||
app.use('/sign-up', require('./routes/sign-up')); | ||
app.use('/comments', require('./routes/comments')) | ||
app.use('/sign-up', require('./routes/sign-up')) | ||
|
||
// 处理登录请求(可能来自登录界面中的表单) | ||
app.post('/login', function (req, res) { | ||
AV.User.logIn(req.body.username, req.body.password).then(function (user) { | ||
let adminMail = process.env.BLOGGER_EMAIL || process.env.SMTP_USER; | ||
if (user.get('email') === adminMail) { | ||
res.saveCurrentUser(user); // 保存当前用户到 Cookie | ||
res.redirect('/comments'); | ||
} | ||
else { | ||
res.redirect('/'); | ||
} | ||
}, function (error) { | ||
//登录失败,跳转到登录页面 | ||
res.redirect('/'); | ||
}); | ||
}); | ||
AV.User.logIn(req.body.username, req.body.password).then(function (user) { | ||
const adminMail = process.env.BLOGGER_EMAIL || process.env.SMTP_USER | ||
if (user.get('email') === adminMail) { | ||
res.saveCurrentUser(user) // 保存当前用户到 Cookie | ||
res.redirect('/comments') | ||
} else { | ||
res.redirect('/') | ||
} | ||
}, function (error) { // 登录失败,跳转到登录页面 | ||
res.redirect('/') | ||
}) | ||
}) | ||
|
||
// 登出账号 | ||
app.get('/logout', function(req, res) { | ||
req.currentUser.logOut(); | ||
res.clearCurrentUser(); // 从 Cookie 中删除用户 | ||
res.redirect('/'); | ||
}); | ||
|
||
app.use(function(req, res, next) { | ||
// 如果任何一个路由都没有返回响应,则抛出一个 404 异常给后续的异常处理器 | ||
if (!res.headersSent) { | ||
var err = new Error('Not Found'); | ||
err.status = 404; | ||
next(err); | ||
} | ||
}); | ||
app.get('/logout', function (req, res) { | ||
req.currentUser.logOut() | ||
res.clearCurrentUser() // 从 Cookie 中删除用户 | ||
res.redirect('/') | ||
}) | ||
|
||
// 唤醒实例 | ||
app.get('/start', function (req, res) { | ||
console.log('成功唤醒实例') | ||
res.send('Success') | ||
}) | ||
|
||
app.use(function (req, res, next) { | ||
// 如果任何一个路由都没有返回响应,则抛出一个 404 异常给后续的异常处理器 | ||
if (!res.headersSent) { | ||
var err = new Error('Not Found') | ||
err.status = 404 | ||
next(err) | ||
} | ||
}) | ||
// error handlers | ||
app.use(function(err, req, res, next) { | ||
app.use(function (err, req, res, next) { | ||
if (req.timedout && req.headers.upgrade === 'websocket') { | ||
// 忽略 websocket 的超时 | ||
return; | ||
return | ||
} | ||
|
||
var statusCode = err.status || 500; | ||
var statusCode = err.status || 500 | ||
if (statusCode === 500) { | ||
console.error(err.stack || err); | ||
console.error(err.stack || err) | ||
} | ||
if (req.timedout) { | ||
console.error('请求超时: url=%s, timeout=%d, 请确认方法执行耗时很长,或没有正确的 response 回调。', req.originalUrl, err.timeout); | ||
console.error('请求超时: url=%s, timeout=%d, 请确认方法执行耗时很长,或没有正确的 response 回调。', req.originalUrl, err.timeout) | ||
} | ||
res.status(statusCode); | ||
res.status(statusCode) | ||
// 默认不输出异常详情 | ||
var error = {}; | ||
var error = {} | ||
if (app.get('env') === 'development') { | ||
// 如果是开发环境,则将异常堆栈输出到页面,方便开发调试 | ||
error = err; | ||
error = err | ||
} | ||
res.render('error', { | ||
message: err.message, | ||
error: error | ||
}); | ||
}); | ||
}) | ||
}) | ||
|
||
app.locals.dateFormat = function (date) { | ||
var vDay = padWithZeros(date.getDate(), 2); | ||
var vMonth = padWithZeros(date.getMonth() + 1, 2); | ||
var vYear = padWithZeros(date.getFullYear(), 2); | ||
var vHour = padWithZeros(date.getHours(), 2); | ||
var vMinute = padWithZeros(date.getMinutes(), 2); | ||
var vSecond = padWithZeros(date.getSeconds(), 2); | ||
// return `${vYear}-${vMonth}-${vDay}`; | ||
return `${vYear}-${vMonth}-${vDay} ${vHour}:${vMinute}:${vSecond}`; | ||
}; | ||
var vDay = padWithZeros(date.getDate(), 2) | ||
var vMonth = padWithZeros(date.getMonth() + 1, 2) | ||
var vYear = padWithZeros(date.getFullYear(), 2) | ||
var vHour = padWithZeros(date.getHours(), 2) | ||
var vMinute = padWithZeros(date.getMinutes(), 2) | ||
var vSecond = padWithZeros(date.getSeconds(), 2) | ||
// return `${vYear}-${vMonth}-${vDay}`; | ||
return `${vYear}-${vMonth}-${vDay} ${vHour}:${vMinute}:${vSecond}` | ||
} | ||
|
||
const padWithZeros = (vNumber, width) => { | ||
var numAsString = vNumber.toString(); | ||
while (numAsString.length < width) { | ||
numAsString = '0' + numAsString; | ||
} | ||
return numAsString; | ||
}; | ||
var numAsString = vNumber.toString() | ||
while (numAsString.length < width) { | ||
numAsString = '0' + numAsString | ||
} | ||
return numAsString | ||
} | ||
|
||
module.exports = app; | ||
module.exports = app |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,74 +1,80 @@ | ||
const AV = require('leanengine'); | ||
const mail = require('./utilities/send-mail'); | ||
const Comment = AV.Object.extend('Comment'); | ||
const request = require('request'); | ||
const spam = require('./utilities/check-spam'); | ||
const AV = require('leanengine') | ||
const mail = require('./utilities/send-mail') | ||
const Comment = AV.Object.extend('Comment') | ||
const axios = require('axios') | ||
const spam = require('./utilities/check-spam') | ||
|
||
function sendNotification(currentComment, defaultIp) { | ||
let ip = currentComment.get('ip') || defaultIp; | ||
console.log('IP: %s', ip); | ||
spam.checkSpam(currentComment, ip); | ||
function sendNotification (currentComment, defaultIp) { | ||
// 发送博主通知邮件 | ||
if (currentComment.get('mail') !== process.env.BLOGGER_EMAIL) { | ||
mail.notice(currentComment) | ||
} | ||
|
||
// 发送博主通知邮件 | ||
bloggerMail = process.env.BLOGGER_EMAIL || process.env.SENDER_EMAIL; | ||
if (currentComment.get('mail') !== bloggerMail) { | ||
mail.notice(currentComment); | ||
} | ||
const ip = currentComment.get('ip') || defaultIp | ||
console.log('IP: %s', ip) | ||
spam.checkSpam(currentComment, ip) | ||
|
||
// AT评论通知 | ||
let rid =currentComment.get('pid') || currentComment.get('rid'); | ||
// AT评论通知 | ||
const rid = currentComment.get('pid') || currentComment.get('rid') | ||
|
||
if (!rid) { | ||
console.log("这条评论没有 @ 任何人"); | ||
return; | ||
} else if (currentComment.get('isSpam')) { | ||
console.log('评论未通过审核,通知邮件暂不发送'); | ||
return; | ||
} | ||
if (!rid) { | ||
console.log('这条评论没有 @ 任何人') | ||
return | ||
} else if (currentComment.get('isSpam')) { | ||
console.log('评论未通过审核,通知邮件暂不发送') | ||
return | ||
} | ||
|
||
let query = new AV.Query('Comment'); | ||
query.get(rid).then(function (parentComment) { | ||
if (parentComment.get('mail') && parentComment.get('mail') !== process.env.BLOGGER_EMAIL) { | ||
mail.send(currentComment, parentComment); | ||
} else { | ||
console.log('被@者匿名,不会发送通知'); | ||
} | ||
|
||
}, function (error) { | ||
console.warn('获取@对象失败!'); | ||
}); | ||
const query = new AV.Query('Comment') | ||
query.get(rid).then(function (parentComment) { | ||
if (parentComment.get('mail') && parentComment.get('mail') !== process.env.BLOGGER_EMAIL) { | ||
mail.send(currentComment, parentComment) | ||
} else { | ||
console.log('被@者匿名,不会发送通知') | ||
} | ||
}, function (error) { | ||
console.warn('获取@对象失败!') | ||
}) | ||
} | ||
|
||
AV.Cloud.afterSave('Comment', function (req) { | ||
let currentComment = req.object; | ||
// 检查垃圾评论 | ||
return sendNotification(currentComment, req.meta.remoteAddress); | ||
}); | ||
|
||
AV.Cloud.define('resend_mails', function(req) { | ||
let query = new AV.Query(Comment); | ||
query.greaterThanOrEqualTo('createdAt', new Date(new Date().getTime() - 24*60*60*1000)); | ||
query.notEqualTo('isNotified', true); | ||
// 如果你的评论量很大,可以适当调高数量限制,最高1000 | ||
query.limit(200); | ||
return query.find().then(function(results) { | ||
new Promise((resolve, reject)=>{ | ||
count = results.length; | ||
for (var i = 0; i < results.length; i++ ) { | ||
sendNotification(results[i], req.meta.remoteAddress); | ||
} | ||
resolve(count); | ||
}).then((count)=>{ | ||
console.log(`昨日${count}条未成功发送的通知邮件处理完毕!`); | ||
}).catch(()=>{ | ||
|
||
}); | ||
}); | ||
}); | ||
const currentComment = req.object | ||
// 检查垃圾评论 | ||
return sendNotification(currentComment, req.meta.remoteAddress) | ||
}) | ||
|
||
AV.Cloud.define('self_wake', function(req) { | ||
request(process.env.ADMIN_URL, function (error, response, body) { | ||
console.log('自唤醒任务执行成功,响应状态码为:', response && response.statusCode); | ||
}); | ||
}); | ||
AV.Cloud.define('resend_mails', function (req) { | ||
const query = new AV.Query(Comment) | ||
query.greaterThanOrEqualTo('createdAt', new Date(new Date().getTime() - 24 * 60 * 60 * 1000)) | ||
query.notEqualTo('isNotified', true) | ||
// 如果你的评论量很大,可以适当调高数量限制,最高1000 | ||
query.limit(200) | ||
return query.find().then(function (results) { | ||
new Promise((resolve, reject) => { | ||
count = results.length | ||
for (var i = 0; i < results.length; i++) { | ||
sendNotification(results[i], req.meta.remoteAddress) | ||
} | ||
resolve(count) | ||
}).then((count) => { | ||
console.log(`昨日${count}条未成功发送的通知邮件处理完毕!`) | ||
}).catch((error) => { | ||
console.error(`昨日未成功发送的通知邮件处理失败:`, error) | ||
}) | ||
}) | ||
}) | ||
|
||
AV.Cloud.define('self_wake', function (req) { | ||
let adminURL = process.env.ADMIN_URL | ||
let location = "/start" | ||
if (adminURL[adminURL.length - 1] === "/") { | ||
location = "start" | ||
} | ||
axios.get(adminURL + location) | ||
.then(function (response) { | ||
console.log('自唤醒任务执行成功,响应状态码为:', response && response.status) | ||
}) | ||
.catch(function (error) { | ||
console.error('自唤醒任务执行失败:', error) | ||
}) | ||
}) |
Oops, something went wrong.