Last active
December 11, 2015 04:29
-
-
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.
This file contains hidden or 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
# 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. '[email protected]' | |
# 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: | |
# [email protected] (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 = '[email protected]' 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