hubot-remind-advanced
Version:
A Hubot script for creating quick reminders through natural language.
137 lines (114 loc) • 4.59 kB
text/coffeescript
# Description:
# Advanced Natural Language Reminder
#
# Configuration:
# HUBOT_REMIND_KEY
#
# Commands:
# hubot remind (me) <note> - Creates a new reminder using <note>
# hubot remind cancel - Cancels the reminder operation
# hubot remind (me) now - Returns all your reminders
# hubot remind clear - Clears all your reminders
#
# Author:
# MrSaints
#
# Notes:
# "tomorrow" doesn't work between 12-4AM because
# the developer of `chrono-node` lives in a strange planet
#
# Terminating the listeners early because of their
# "colliding" regular expressions
chrono = require "chrono-node"
moment = require "moment"
HUBOT_REMIND_KEY = process.env.HUBOT_REMIND_KEY or "_remind"
class Reminder
constructor: (@callback) ->
@pending = []
@crons = []
addPending: (user, message) ->
reminder = @getPending user
return [false, reminder] if reminder isnt false
payload = [user, message]
@pending.push payload
[true, payload]
cancelPending: (user) ->
if reminder = @getPending user
@pending.splice @pending.indexOf(reminder), 1
return true
false
getPending: (user) ->
for reminder, index in @pending
return reminder if reminder[0].id is user.id
false
complete: (user, executionDate) ->
if reminder = @getPending user
@addCron reminder[0], reminder[1], executionDate
@pending.splice @pending.indexOf(reminder), 1
return [reminder[0], reminder[1], executionDate]
false
addCron: (user, message, executionDate) ->
console.log "hubot-remind-advanced: Adding cron job."
newTask = setTimeout =>
@callback user, message
, moment(executionDate).diff()
@crons.push newTask
clearCron: ->
for cron in @crons
clearTimeout cron
@crons = []
module.exports = (robot) ->
BrainReminders = ->
robot.brain.data[HUBOT_REMIND_KEY] or= []
Reminder = new Reminder (user, message, executionDate) ->
message = "Reminder for @#{user.name}: #{message}"
robot.send {room: user.room, user: user}, message
old = [user, message, executionDate]
BrainReminders().splice BrainReminders().indexOf old, 1
robot.respond /remind cancel/i, id: "remind.cancel", (res) ->
if Reminder.cancelPending res.message.user
res.reply "Your reminder operation has been cancelled."
else
res.reply "You have no reminders pending creation."
res.finish()
robot.respond /remind( me)? now/i, id: "remind.list", (res) ->
message = ""
for reminder in BrainReminders()
if reminder[0].id is res.message.user.id
message += "[#{moment(reminder[2]).fromNow()}] "
message += "#{reminder[1]}\n"
res.reply message if message.length isnt 0
res.finish()
robot.respond /remind clear/i, id: "remind.clear", (res) ->
Reminder.clearCron()
cleared = 0
for reminder in BrainReminders()
if reminder[0].id is res.message.user.id
++cleared
BrainReminders().splice reminder, 1
if cleared isnt 0
res.reply "#{cleared} of your reminder(s) have been cleared."
else
res.reply "You have no reminders."
res.finish()
robot.respond /remind( me)? (.+)/i, id: "remind.new", (res) ->
[status, reminder] = Reminder.addPending res.message.user, res.match[2]
if status isnt false
res.reply "When should I remind you?"
else
res.reply "You have a reminder pending creation. When should I remind you \"#{reminder[1]}\" ?"
res.finish()
robot.hear /(.+)/i, id: "remind.process", (res) ->
return unless Reminder.pending.length isnt 0
chronoDate = chrono.parse res.match[1]
return unless chronoDate.length isnt 0 # Should probably handle this?
executionDate = chronoDate[0].start.date()
if reminder = Reminder.complete res.message.user, executionDate
humanized = moment(executionDate).fromNow()
res.reply "Reminder added. I'll remind you #{humanized}."
BrainReminders().push reminder
robot.brain.save()
robot.brain.on "loaded", ->
robot.logger.info "hubot-remind-advanced: Loading reminders from brain."
for reminder, index in BrainReminders()
Reminder.addCron reminder[0], reminder[1], reminder[2]