Skip to content

Instantly share code, notes, and snippets.

@hlung
Last active December 11, 2015 04:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hlung/4545901 to your computer and use it in GitHub Desktop.
Save hlung/4545901 to your computer and use it in GitHub Desktop.
Automatically nags "non-offline" people in a room at a particular time to enter something.
# Description:
# Automatically nags "non-offline" people in a room at a particular time interval to enter something.
#
# Dependencies:
# cron, time, node-xmpp
#
# Configuration:
# HIPCHAT_STANDUP_ROOM_JID e.g. '13184_botlab@conf.hipchat.com'
# HIPCHAT_STANDUP_TIMEZONE e.g. "Asia/Bangkok" or "Europe/Paris" or "America/New_York"
# HIPCHAT_STANDUP_CRON_TIME e.g. '0 0 14-18 * * 1-5' means weekdays, every hour from 2-6PM
#
# Commands:
#
#
# Author:
# hlung@oozou.com (Fri 19 Oct 2012)
# MIT License
#
#-------------------------------------------------
# turn on debug mode settings, console.log every 10 sec in botlab room
DEBUG = 0
CRON_TIME_EV1SEC = '* * * * * *' # time pattern 'sec min hr monthDay month weekDay'
CRON_TIME_EV10SEC = '*/10 * * * * *' # "1-9/2" is the same as "1,3,5,7,9".
CRON_TIME_2to6PM_WEEKDAY = '0 */30 12-18 * * MON-FRI'
CRON_TIME = process.env.HIPCHAT_STANDUP_CRON_TIME or CRON_TIME_2to6PM_WEEKDAY
TIMEZONE = process.env.HIPCHAT_STANDUP_TIMEZONE or "" # empty str = system tz
STANDUP_ROOM_JID = process.env.HIPCHAT_STANDUP_ROOM_JID # 13184_botlab 13184_standup
ROOM_RPY = { "reply_to": STANDUP_ROOM_JID } # room that the bot should reply to
BOT_FULLNAME = process.env.HUBOT_HIPCHAT_NAME + " Bot"
maxHistoryStanzas = 40 # should be more than conversation a day
_isCronStarted = 0
_bot = null
# --- DEBUG overrides ---
CRON_TIME = CRON_TIME_EV10SEC if DEBUG
STANDUP_ROOM_JID = '13184_botlab@conf.hipchat.com' if DEBUG
# (Name string: Date object) of last conversation in STANDUP_ROOM_JID
# e.g. { 'Hlung K': Wed Oct 17 2012 16:24:27 GMT+0700 (ICT), 'Ing W': Tue Oct 09 2012 12:46:28 GMT+0700 (ICT) }
STANDUP_LAST_CONVER = {}
# Online status of members in STANDUP_ROOM_JID
# e.g. { 'Pop T': true, 'Pete R.': false }
STANDUP_MEMBER_STATUS = {}
CRONJOB = require('cron').CronJob
TIME = require('time')
xmpp = require('node-xmpp')
#-------------------------------------------------
# --------------------
# Get robot var for using in sending messages later on.
# --------------------
module.exports = (robot) ->
_bot = robot
# list people that are online in standup room
robot.respond /people online|online people/i, (msg) ->
onlineMembers = []
roomMembers = for name, online of STANDUP_MEMBER_STATUS
if online
onlineMembers.push '@' + name.split(' ')[0].toLowerCase()
onlineMembers = onlineMembers.sort()
msg.send "People online in Standup room: " + onlineMembers.join(" ")
###
robot.hear /.?/, (msg) ->
if msg.message.user.reply_to is STANDUP_ROOM_JID
console.log "got some msg in standup room"
###
# --------------------
# Connected
# --------------------
_bot.adapter.bot.on 'connect', =>
console.log 'Standup: connected, starting cron job...'
# NOTE: explicitly join again to request chat history since 'wobot 0.8.0' blocks this
_bot.adapter.bot.join STANDUP_ROOM_JID, maxHistoryStanzas # bot.join (roomJid, maxHistoryStanzas)
startCron()
#doNag() # calling right after connect doesn't work
# --------------------
# Collect Data
# --------------------
_bot.adapter.bot.on 'data', =>
stanza = arguments[0]
return unless stanza
# --- Message ---
if stanza.is("message") and stanza.attrs.type is "groupchat"
body = stanza.getChildText("body")
return unless body
fromJid = new xmpp.JID(stanza.attrs.from)
fromChannel = fromJid.bare().toString()
fromNick = fromJid.resource
#console.log fromJid, fromChannel, fromNick
# Ignore bot name
regex = new RegExp(BOT_FULLNAME,"i");
return if regex.test(fromNick)
if fromChannel is STANDUP_ROOM_JID
delay = stanza.getChild("delay")
time = null
if delay
time = new Date(Date.parse(delay.attrs.stamp)) # 2012-10-16T04:10:18Z
else
time = new Date()
STANDUP_LAST_CONVER[fromNick] = time if time
# --- Presence ---
else if stanza.is("presence")
fromJid = new xmpp.JID(stanza.attrs.from)
fromChannel = fromJid.bare().toString()
fromNick = fromJid.resource
# Ignore bot name
regex = new RegExp(BOT_FULLNAME,"i");
return if regex.test(fromNick)
if fromChannel is STANDUP_ROOM_JID
isAvailable = false
# only 'unavailable' or null is supplied
isAvailable = true if stanza.attrs.type isnt "unavailable"
STANDUP_MEMBER_STATUS[fromNick] = isAvailable
# record for all rooms
#if stanza.attrs.type isnt "unavailable"
# ROOM_PEOPLE
# Start scheduling
# --------------------
startCron = () ->
unless _isCronStarted
_isCronStarted = 1 # prevent starting cron twice
new CRONJOB(CRON_TIME, ->
doNag()
, true, TIMEZONE)
# Notify online members that haven't put anything in today :)
# --------------------
doNag = () ->
console.log 'Standup: try nagging on', (new Date()).toString()
#console.log STANDUP_MEMBER_STATUS, STANDUP_LAST_CONVER
startOfToday = getStartOfToday()
membersToNotify = []
roomMembers = for name, online of STANDUP_MEMBER_STATUS
if online
chatTime = STANDUP_LAST_CONVER[name]
lastChatDate = new TIME.Date(chatTime) if chatTime
if (!chatTime) or (lastChatDate < startOfToday)
membersToNotify.push '@' + name.split(' ')[0].toLowerCase()
membersToNotify = membersToNotify.sort()
msg = null
if membersToNotify
switch membersToNotify.length
when 0
console.log 'Standup: Everyone stood up. No one to notify.'
when 1
callings = ["you can do it!", "your turn","(yuno)"]
msg = "C'mon " + membersToNotify[0] + " " + random callings
else
callings = ["Please standup!", "Standup please...", "What are you doing today?"]
msg = membersToNotify.join(" ") + " " + random callings
console.log msg if msg
say msg unless DEBUG
# This works after bot joins the room.
# So call it inside some CronJob or setInterval(fun,dur,obj)
# --------------------
say = (strings) -> _bot.send(ROOM_RPY, strings) if strings
# other helpers
# -----------------
getStartOfToday = ->
day = new TIME.Date()
day.setTimezone TIMEZONE
#log "after", day.getHours()
#log "tz", day.getTimezone()
day.setHours 0
day.setMinutes 0
day.setSeconds 0
#console.log day.toString()
#log '-----'
day
# pick one random element in an array
random = (array) ->
return nil unless array
array[Math.floor(Math.random() * array.length)]
# print everything in a variable
util = require('util');
inspect = (va) -> console.log(util.inspect(va, false, null));
log = (str...) => console.log str...
type = (obj) ->
if obj == undefined or obj == null
return String obj
classToType = new Object
for name in "Boolean Number String Function Array Date RegExp".split(" ")
classToType["[object " + name + "]"] = name.toLowerCase()
myClass = Object.prototype.toString.call obj
if myClass of classToType
return classToType[myClass]
return "object"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment