diff --git a/package.json b/package.json index e2e2016..2d462c4 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,9 @@ "hubot-rules": "^0.1.1", "hubot-scripts": "^2.16.1", "hubot-shipit": "^0.2.0", - "hubot-slack": "^3.3.0" + "hubot-slack": "^3.3.0", + "fast-levenshtein": "^2.0.6", + "js-yaml": "^3.9.1" }, "engines": { "node": "0.10.x" diff --git a/scripts/pizza.coffee b/scripts/pizza.coffee index 6ec1da7..ac51985 100644 --- a/scripts/pizza.coffee +++ b/scripts/pizza.coffee @@ -21,55 +21,91 @@ # Author: # StijnP (XAOP) # +levenshtein = require 'fast-levenshtein' +yaml = require 'js-yaml' module.exports = (robot) -> - robot.brain.data.currentPizzaOrder = - pizzas: {}, - date: null, - status: null + pazza_menu = ['funghi', 'mano', 'rochus', 'margherita', 'carbonara', 'prosciutto', 'fratello', 'capricciosa', 'calzione', '4stagioni', 'rimini', 'vesuvio', 'vulcano', 'hawaii', 'peppina', 'napoletana', 'romana', 'extravaganza', '8gusti', 'pazza', 'boscaiola', 'montana', 'primavera', 'parmigiana', 'pollo', 'pescatore', '4formaggi', '6formaggi', 'scampis', 'bruschetta', 'toscana', 'patapizza'] + match_pizza = (order) -> + # Normalization + replacements = [[/seizoene(n)?/, "stagioni"], + [/kaze(n)?/, "formaggi"], + [/fromage(s)?/, "formaggi"], + [/fromaggi(o)?/, "formaggi"], + [/quat(t)?r(o|e)/, "4"], + [/sei/, "6"], + [/octo/, "8"], + [/vier/, "4"], + [/zes/, "6"], + [/acht/, "8"], + [/4 s/, "4s"], + [/4 f/, "4f"], + [/6 f/, "6f"], + [/8 g/, "8g"], + [/random/, pazza_menu[Math.round(Math.random()*pazza_menu.length)-1]]] + normalized = replacements.reduce(((s, r) -> + s.replace(r[0], r[1])), order.toLowerCase()) + return normalized.split(" ").map((norm_word) -> + pazza_menu.map((menu_item) -> + [levenshtein.get(norm_word, menu_item), menu_item] + ).sort()[0] + ).sort()[0][1] + robot.brain.data.pizzaOrderHistory = robot.brain.data.pizzaOrderHistory or [] robot.brain.data.pizzaOrderHistoryBackup = robot.brain.data.pizzaOrderHistoryBackup or [] pizzas = + currentOrder: -> + robot.brain.data.currentPizzaOrder + current: -> - obj = robot.brain.data.currentPizzaOrder.pizzas - Object.keys(obj).map((key) -> - obj[key] - ).join() + obj = this.currentOrder().pizzas + counted = yaml.safeDump(Object.keys(obj).reduce(((p, c) -> + if p[obj[c]] + p[obj[c]] += 1 + else + p[obj[c]] = 1 + return p + ), {})) + start: -> - robot.brain.data.currentPizzaOrder.status = 'open' + order = this.currentOrder() + if this.isStarted() + unless order.startDate && order.startDate >= new Date(new Date() - 24 * 60 * 60 * 1000) + this.closeOrder() + order.status = 'open' + order.startDate = order.startDate || new Date() isStarted: -> - robot.brain.data.currentPizzaOrder.status == 'open' + this.currentOrder().status == 'open' currentQty: -> - Object.keys(robot.brain.data.currentPizzaOrder.pizzas).length + Object.keys(this.currentOrder().pizzas).length currentEaters: -> - Object.keys(robot.brain.data.currentPizzaOrder.pizzas).join() + Object.keys(this.currentOrder().pizzas).join() add: (user, name) -> # only 1 pizza per user atm - robot.brain.data.currentPizzaOrder.pizzas[user] = name + this.currentOrder().pizzas[user] = name remove: (user) -> - delete robot.brain.data.currentPizzaOrder.pizzas[user] + delete this.currentOrder().pizzas[user] true closeOrder: -> if pizzas.currentQty() > 0 - robot.brain.data.currentPizzaOrder.date = new Date() - robot.brain.data.currentPizzaOrder.status = 'closed' - order = robot.brain.data.currentPizzaOrder + order = this.currentOrder() + order.date = new Date() + order.status = 'closed' robot.brain.data.pizzaOrderHistory.push order - pizzas.clearOrder() + pizzas.newOrder() order else - - clearOrder: -> + newOrder: -> robot.brain.data.currentPizzaOrder = {pizzas: {}, date: null, status: null} clearHistory: -> @@ -85,6 +121,8 @@ module.exports = (robot) -> pizza_qty += Object.keys(order.pizzas).length "#{pizza_qty} pizzas ordered in #{order_qty} orders" + pizzas.newOrder() + ## HELP ## robot.respond /pizza help/i, (msg) -> msg.send "Order a pizza: '@hubby pizza me your-pizza-choice'" @@ -98,26 +136,47 @@ module.exports = (robot) -> robot.respond /pizza me (.*)/i, (msg) -> if pizzas.isStarted() sender = msg.message.user.name.toLowerCase() - pizza = msg.match[1] + if /special/i.test(msg.match[1]) + pizza = msg.match[1].slice(8) + else + pizza = match_pizza(msg.match[1]) pizzas.add(sender, pizza) msg.reply "One pizza #{pizza} ordered, now #{pizzas.currentQty()} on the list" else msg.send "Sorry, no running order at this time..." + ## ORDER a pizza for someone else ## + robot.respond /pizza for (\S+) (.*)/i, (msg) -> + if pizzas.isStarted() + external = "#{msg.message.user.name.toLowerCase()} for #{msg.match[1]}" + if /special/i.test(msg.match[2]) + pizza = msg.match[2].slice(8) + else + pizza = match_pizza(msg.match[2]) + pizzas.add(external, pizza) + msg.reply "One pizza #{pizza} ordered by #{external}, now #{pizzas.currentQty()} on the list" + else + msg.send "Apologize to #{msg.match[1]} for me, no running order at this time..." + ## CANCEL your pizza order robot.hear /no pizza for me/i, (msg) -> sender = msg.message.user.name.toLowerCase() pizzas.remove(sender) msg.reply "Ok... I cancelled your order... pussy" + ## CANCEL someone's pizza order + robot.respond /no pizza for (\S+)/i, (msg) -> + external = "#{msg.message.user.name.toLowerCase()} for #{msg.match[1]}" + pizzas.remove(external) + msg.reply "Ok... tell #{msg.match[1]} their order is cancelled" + ## SHOW CURRENT order round ## robot.respond /pizza (current|show)/i, (msg) -> qty = pizzas.currentQty() if qty > 0 heroes = pizzas.currentEaters() names = pizzas.current() - msg.send "#{qty} pizzas: #{names}" - msg.send "Pizza heroes of today are #{heroes}" + msg.send "#{qty} pizzas:\n#{names}Pizza heroes of today are #{heroes}" # msg.send "Status is '#{robot.brain.data.currentPizzaOrder.current}'" else msg.send "No orders yet" @@ -146,8 +205,7 @@ module.exports = (robot) -> names = pizzas.current() order = pizzas.closeOrder() msg.send "Pizza order CLOSED, you should now order:" - msg.send "#{qty} pizzas: #{names}" - msg.send "Pizza heroes of today are #{heroes}" + msg.send "#{qty} pizzas:\n#{names}Pizza heroes of today are #{heroes}" else msg.send "Nothing to close, you need to order first, silly! :pizza:"