diff --git a/config/default.coffee b/config/default.coffee index ac5ce60..a7b496a 100644 --- a/config/default.coffee +++ b/config/default.coffee @@ -1,3 +1,4 @@ module.exports = port: 8201 dbPath: 'db' + webhookUrl: null diff --git a/package.json b/package.json index ad04926..89a41b1 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "graceful-logger": "^0.4.3", "lodash": "^4.0.1", "moment": "^2.11.1", - "nedb": "^1.7.2" + "nedb": "^1.7.2", + "request": "^2.69.0" } } diff --git a/src/bot.coffee b/src/bot.coffee index 0eae3f5..2e80e1c 100644 --- a/src/bot.coffee +++ b/src/bot.coffee @@ -1,25 +1,148 @@ config = require 'config' +cron = require 'cron' +_ = require 'lodash' +Promise = require 'bluebird' +logger = require 'graceful-logger' +moment = require 'moment' +{CronJob} = cron +request = require 'request' + +requestAsync = Promise.promisify request + model = require './model' +rules = require './rules' class Bot -module.exports = (app) -> + isActive: -> + config.activeDate is moment().format('YYYYMMDD') + + active: -> + config.activeDate = moment().format('YYYYMMDD') + +bot = new Bot + +_messageHandler = (req, res) -> + return res.status(400).send("Missing creator") unless req.body.creator + + # 动态记录频道 id,以便发送记录 + if req.body._storyId + config._targetId = req.body._storyId + config.targetType = 'story' + else if req.body._roomId + config._targetId = req.body._roomId + config.targetType = 'room' + + bot.active() + + checkinData = + _creatorId: req.body.creator._id + name: req.body.creator.name + time: Date.now() + + model.addCheckin checkinData + + .then -> + + # 提取回复规则 + replyRule = null + rules.replies.some (reply) -> + switch + when reply.match and req.body.body?.match(reply.match) + replyRule = reply + return true + else return false + + return res.status(200).send('ok') unless replyRule + + # 构造回复消息 + replyMsg = + switch + when replyRule.msg + replyRule.msg = [replyRule.msg] if toString.call(replyRule.msg) is '[object String]' + replyMsg = replyRule.msg[_.random(0, replyRule.msg.length - 1)] + + return res.status(200).send('ok') unless replyMsg - bot = new Bot + # 预处理回复消息 + if rules.replaces + for key, val of rules.replaces + replyMsg = replyMsg.replace key, val - app.post '/messages', (req, res) -> + # 构造消息结构 + message = content: replyMsg + # 回应消息 + res.status(200).send message - return res.status(400).send({error: "Missing creator"}) unless req.body.creator + .catch (err) -> res.status(400).send error: err.message + +_sendCheckinSummary = -> + return unless bot.isActive() + return unless rules.members and config._targetId and config.webhookUrl + model.getCheckins().then (checkins) -> + nonCheckMembers = rules.members.filter (memberName) -> + return false if checkins._creatorId is memberName + return false if checkins.name.indexOf(memberName) > -1 + return true + if nonCheckMembers.length + msg = "#{nonCheckMembers.join(',')} 这几个家伙还没签到,去哪儿啦?" + else + msg = "大家来的好早,每一位都签到啦" + + message = content: msg + + switch config.targetType + when 'story' then message._storyId = config._targetId + when 'room' then message._roomId = config._targetId + else return false + + requestAsync + method: 'POST' + url: config.webhookUrl + json: true + body: message + + .catch (err) -> logger.warn err.stack + +_sendCronData = (cronData) -> + + return -> + + return unless bot.isActive() + return unless config.webhookUrl and config._targetId and cronData.msg + + message = content: msg + + switch config.targetType + when 'story' then message._storyId = config._targetId + when 'room' then message._roomId = config._targetId + else return false + + console.log "Send message", + method: 'POST' + url: config.webhookUrl + json: true + body: message + + requestAsync + method: 'POST' + url: config.webhookUrl + json: true + body: message + .catch (err) -> logger.warn err.stack + +module.exports = (app) -> - checkinData = - _creatorId: req.body.creator._id - name: req.body.creator.name - time: Date.now() + app.post '/incoming', (req, res) -> + _messageHandler req, res - model.addCheckin checkinData + app.use (err, req, res, next) -> + res.status(500).send error: err.message - .then -> res.status(200).send ok: 1 + new CronJob '0 0 10 * * 1-5', _sendCheckinSummary - .catch (err) -> res.status(400).send error: err.message + if rules.crons + for cronRule, cronData of rules.crons + new CronJob cronRule, _sendCronData(cronData) bot diff --git a/src/rules.coffee b/src/rules.coffee index e69de29..29bb54b 100644 --- a/src/rules.coffee +++ b/src/rules.coffee @@ -0,0 +1,45 @@ +moment = require 'moment' + +module.exports = rules = + replies: [ + match: /.*/ + msg: [ + '%welcome,安排一下今天的计划吧~' + '%welcome,我是偷工减料的签到机器人' + '我实在是找不出还有什么话能回复了' + '您先忙着,我去去就来' + '你是猴子请来的救兵吗' + '我喊你一声你敢应吗' + ] + ] + # 列表中的成员如果没有签到,会在 10 点收到通知 + members: [ + '博深' + '陈涌' + '丹青' + '品章' + '砰砰' + '王连杰' + '王卫' + '晶鑫' + '王艺霖' + '徐亮' + '郁飞' + '晓连' + '俊官' + ] + # 替换 msg 中的字符串 + replaces: + '%welcome': -> + txt = '' + hour = moment().hour() + switch + when hour > 7 and hour < 9 then txt = '早上好' + when hour >= 9 and hour < 11 then txt = '上午好' + when hour >= 11 and hour < 13 then txt = '中午好' + when hour >=13 and hour < 18 then txt = '下午好' + else txt = '晚上好' + txt + crons: + '0 0 18 * * 1-5': + msg: '忙碌了一天,大家都辛苦啦,好好休息吧' diff --git a/test/main.coffee b/test/main.coffee index 957e051..4c1bb95 100644 --- a/test/main.coffee +++ b/test/main.coffee @@ -13,29 +13,31 @@ describe 'Bot', -> it 'should record the first checkin time of user', (done) -> - request(app).post '/messages' + request(app).post '/incoming' .set 'Content-Type': 'application/json' .send creator: _id: 1 name: 'xxx' body: 'Hello' + event: 'message.create' .end (err, res) -> - res.body.should.eql ok: 1 + res.statusCode.should.eql 200 done err it 'should update the last visit time of user', (done) -> # Checkin again - request(app).post '/messages' + request(app).post '/incoming' .set 'Content-Type': 'application/json' .send creator: _id: 1 name: 'xxx' body: 'Hello Again' + event: 'message.create' .end (err, res) -> - res.body.should.eql ok: 1 + res.statusCode.should.eql 200 done err it 'should get all the checkin data', (done) ->