├── .gitignore ├── README.md ├── bot.py ├── plugins ├── __init__.py └── notes.py ├── requirements.txt └── slackbot_settings.py /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | *.pyc 3 | *# 4 | *~ 5 | *.swp 6 | #* 7 | local_settings.py 8 | /build 9 | /dist 10 | /*.egg-info 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Slack Notebot 2 | 3 | A meeting notes bot to help take and distribute notes. 4 | 5 | ### Starting the bot 6 | 7 | Create Slack Bot API token at: [https://my.slack.com/services/new/bot](https://my.slack.com/services/new/bot) (See [https://api.slack.com/bot-users](https://api.slack.com/bot-users) for additional info) 8 | 9 | Run `bot.py` with the `SLACK_API_TOKEN` environment variable set: 10 | 11 | ``bash 12 | $ SLACK_API_TOKEN='xxxxxxx' python bot.py 13 | `` 14 | 15 | ### Using the bot 16 | 17 | Private message the bot with the words `start`. 18 | 19 | Start typing meeting notes. Users that are `@mentioned` will be remembered and sent a transcript of the notes at the end of the session. 20 | 21 | Type `finished` to end the notes session. 22 | 23 | This is what a typical notes session might look like: 24 | 25 | ![http://i.imgur.com/J4X65Sv.png](http://i.imgur.com/J4X65Sv.png) 26 | 27 | ### Warnings 28 | 29 | The bot just stores incoming meeting notes messages unencrypted into memory. Buyer beware. 30 | -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | import logging 5 | import logging.config 6 | from slackbot import settings 7 | from slackbot import dispatcher 8 | from slackbot.bot import Bot 9 | 10 | # monkey patch slackbot -__- 11 | def new_filter(self, msg): 12 | text = msg.get('text', '') 13 | msg['text'] = text 14 | return msg 15 | dispatcher.MessageDispatcher.filter_text = new_filter 16 | 17 | def main(): 18 | kw = { 19 | 'format': '[%(asctime)s] %(message)s', 20 | 'datefmt': '%m/%d/%Y %H:%M:%S', 21 | 'level': logging.DEBUG, 22 | 'stream': sys.stdout, 23 | } 24 | logging.basicConfig(**kw) 25 | logging.getLogger('requests.packages.urllib3.connectionpool').setLevel(logging.DEBUG) 26 | 27 | settings.API_TOKEN = os.environ['SLACK_API_TOKEN'] 28 | Bot().run() 29 | 30 | if __name__ == '__main__': 31 | main() 32 | -------------------------------------------------------------------------------- /plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dz/slack-notebot/e3485811231c6e5a37fb4a0d7f1cceb1bd717001/plugins/__init__.py -------------------------------------------------------------------------------- /plugins/notes.py: -------------------------------------------------------------------------------- 1 | from slackbot.bot import respond_to 2 | from slackbot.bot import listen_to 3 | from itertools import chain 4 | import re 5 | 6 | AT_USER_MATCHER = re.compile(r'(\<@(\w+)\>)') 7 | 8 | NoteStore = {} 9 | 10 | def start_taking(userid): 11 | NoteStore[userid] = [] 12 | 13 | def stop_taking(userid, message): 14 | 15 | def send_dm(uid, text): 16 | message._client.send_message(uid, text) 17 | 18 | message.reply("*Finished. Collating and distributing.*") 19 | client = message._client 20 | notes = NoteStore.pop(userid, []) 21 | users = client.users 22 | user_ids = list(chain.from_iterable([get_user_ids(note) for note in notes])) 23 | user_names = [users[uid].get('name', '???') for uid in user_ids if uid in users] 24 | sender_name = users[userid].get('name', '???') 25 | collated = "\n".join(replace_user_ids(note, users) for note in notes) 26 | meeting_notes = "```%s```" % collated 27 | message.reply(meeting_notes) 28 | if len(user_names) > 0: 29 | message.reply("Sending above to %s" % ", ".join("@%s" % name for name in user_names)) 30 | for uid in user_ids: 31 | send_dm(uid, "@%s took some notes and is sharing it with you:" % sender_name) 32 | send_dm(uid, meeting_notes) 33 | message.reply("Thank you for using Notebot") 34 | 35 | def add_note(userid, note): 36 | NoteStore[userid].append(note) 37 | 38 | def get_user(message): 39 | return message.body['user'] 40 | 41 | def get_text(message): 42 | return message.body['text'] 43 | 44 | def user_is_taking_notes(userid): 45 | return userid in NoteStore 46 | 47 | def get_user_ids(text): 48 | return [m[1] for m in AT_USER_MATCHER.findall(text)] 49 | 50 | def replace_user_ids(text, users): 51 | user_ids = [m[1] for m in AT_USER_MATCHER.findall(text)] 52 | for uid in user_ids: 53 | text = text.replace("<@%s>" % uid, "@%s" % users.get(uid, {}).get('name', '??')) 54 | return text 55 | 56 | @respond_to('^start$') 57 | def start_notes(message): 58 | userid = get_user(message) 59 | text = get_text(message) 60 | if user_is_taking_notes(userid): 61 | add_note(userid, text) 62 | else: 63 | message.reply('*Starting notes*') 64 | message.reply('(Type `finished` to stop taking notes)') 65 | start_taking(userid) 66 | 67 | @respond_to('^finished$') 68 | def finish_notes(message): 69 | userid = get_user(message) 70 | text = get_text(message) 71 | if user_is_taking_notes(userid): 72 | stop_taking(userid, message) 73 | else: 74 | message.reply('Error. Type `start` to start taking notes') 75 | 76 | @respond_to('(.*)') 77 | def take_notes(message, something): 78 | userid = get_user(message) 79 | text = get_text(message) 80 | if text == "finished" or text == "start": 81 | return 82 | if user_is_taking_notes(userid): 83 | add_note(userid, text) 84 | else: 85 | message.reply('Error. Type `start` to start taking notes') 86 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests>=2.4.0 2 | websocket-client>=0.22.0 3 | importlib>=1.0.3 4 | slacker>=0.5.5 5 | slackbot>=0.2.3 6 | -------------------------------------------------------------------------------- /slackbot_settings.py: -------------------------------------------------------------------------------- 1 | PLUGINS = [ 2 | 'plugins', 3 | ] 4 | --------------------------------------------------------------------------------