async def incoming(self, msg): """ Handler for the incoming events of type 'message' Create a message object from the incoming message and sent it to the plugins :param msg: incoming message :return: """ logger.debug('Message handler received %s', msg) slack = registry.get('slack') message = await SlackMessage.from_raw(msg, slack) if not message.frm: # Message without frm (i.e: slackbot) logger.debug('Ignoring message without frm') return if isinstance(self._save, list) and message.subtype in self._save \ or self._save is True: try: db = registry.get('database') await self._save_incoming(message, db) except IntegrityError: logger.debug('Message "%s" already saved. Aborting.', message.timestamp) return if message.frm.id in (self.bot.id, self.bot.bot_id): logger.debug('Ignoring message from ourselves') return await self._dispatch(message, slack)
async def _incoming(self, request): data = await request.post() data = {**data} if data['token'] != self._token: return Response(text='Invalid') logger.debug('Command handler received: %s', data['command']) slack = registry.get('slack') func = self._endpoints.get(data['command']) if not func: raise SlackUnknownCommand(data['command']) command = await SlackCommand.from_raw(data, slack) if isinstance(self._save, list) and data['command'] in self._save \ or self._save is True: logger.debug('Saving incoming command %s from %s', command.command, command.frm.id) db = registry.get('database') await database.__dict__[db.type].dispatcher.save_incoming_command( db, command) await db.commit() coroutine = func(command, slack) ensure_future(coroutine=coroutine, loop=self._loop, logger=logger) return Response(status=200)
async def _incoming(self, event): logger.debug('Event handler received: %s', event) slack = registry.get('slack') if isinstance(self._save, list) and event['type'] in self._save \ or self._save is True: db = registry.get('database') await self._store_incoming(event, db) for func in self._endpoints.get(event['type'], list()): f = func(event, slack) ensure_future(coroutine=f, loop=self._loop, logger=logger)
async def _delete(self, id_, db=None): if not db: db = registry.get('database') await database.__dict__[db.type].group.delete(db, id_) await db.commit()
async def send_issue_msg(self, issue, color): att = Attachment(fallback='issue {}'.format(issue.data['action']), color=color, text='*<{url}|{title}>*\n{body}'.format( url=issue.data['issue']['html_url'], title=issue.data['issue']['title'], body=issue.data['issue']['body']), title='Issue {action} in <{repo_url}|{name}>'.format( repo_url=issue.data['repository']['html_url'], name=issue.data['repository']['name'], action=issue.data['action'], ), author_icon=issue.data['sender']['avatar_url'], author_name=issue.data['sender']['login'], author_link=issue.data['sender']['html_url'], footer=', '.join( label['name'] for label in issue.data['issue']['labels'])) slack = registry.get('slack') channel = await slack.channels.get( name=self.config['github']['channel']) msg = SlackMessage(to=channel) msg.attachments.append(att) await slack.send(msg)
async def send_pr_msg(self, pr, action, color): footer = '+ {add} / - {del_}'.format( add=pr.data['pull_request']['additions'], del_=pr.data['pull_request']['deletions']) att = Attachment(fallback='pull request {}'.format(action), title='Pull request {action} in <{repo_url}|{name}>:' ' <{url}|{title}>'.format( repo_url=pr.data['repository']['html_url'], url=pr.data['pull_request']['html_url'], name=pr.data['repository']['name'], action=pr.data['action'], title=pr.data['pull_request']['title'], ), color=color, text='*<{url}|{title}>*\n{body}'.format( url=pr.data['pull_request']['html_url'], title=pr.data['pull_request']['title'], body=pr.data['pull_request']['body']), author_icon=pr.data['sender']['avatar_url'], author_name=pr.data['sender']['login'], author_link=pr.data['sender']['html_url'], footer=footer) slack = registry.get('slack') channel = await slack.channels.get( name=self.config['github']['channel']) msg = SlackMessage(to=channel) msg.attachments.append(att) await slack.send(msg)
async def start(self): logger.debug('Starting slack plugin') db = registry.get('database') if db.type not in SUPPORTED_DATABASE: raise SlackSetupError('Database must be one of %s', ', '.join(SUPPORTED_DATABASE)) await self._create_db_table() slack = self.factory() sync.add_to_slack(slack) if self._rtm_client: data = await self._http_client.rtm_connect() self.bot = await self._users.get(data['self']['id']) self.bot.type = 'rtm' self._dispatcher['message'].bot = self.bot self._dispatcher['event'].bot = self.bot await self._rtm_client.connect(url=data['url']) else: self.bot = User(id_='B000000000') self.bot.type = 'event' if 'message' in self._dispatcher: self._dispatcher['message'].bot = self.bot if 'event' in self._dispatcher: self._dispatcher['event'].bot = self.bot self._started = True
async def _add(self, group, db=None): if not db: db = registry.get('database') await database.__dict__[db.type].group.add(db, group) await db.commit()
async def get(self, id_=None, fetch=False): db = registry.get('database') data = await database.__dict__[db.type].group.find(db, id_) if data and (fetch or data['last_update'] < (time.time() - self._refresh)): group = await self._query(id_) if group: await self._add(group, db=db) else: await self._delete(group, db=db) elif data: group = Group(id_=data['id'], raw=json.loads(data['raw']), last_update=data['last_update']) else: logger.debug( 'Group "%s" not found in the channel store. ' 'Querying the Slack API', id_) group = await self._query(id_) if group: await self._add(group, db=db) return group
async def thread(self, message, limit=20): db = registry.get('database') thread_ts = message.thread or message.timestamp raw_msgs = await database.__dict__[db.type].message.get_thread( db, thread_ts, limit) messages = await self._create_object(raw_msgs) return messages
async def _create_object(self, raw_msgs): slack = registry.get('slack') messages = list() for raw_msg in raw_msgs: message = await SlackMessage.from_raw(data=raw_msg['raw'], slack=slack) messages.append(message) return messages
async def _add(self, channel, db=None): """ Add a channel to the channel store """ if not db: db = registry.get('database') await database.__dict__[db.type].channel.add(db, channel) await db.commit()
async def _create_db_table(self): db = registry.get('database') await db.execute(''' CREATE TABLE IF NOT EXISTS candy ( user TEXT PRIMARY KEY NOT NULL, candy INT DEFAULT 0 ) ''') await db.set_plugin_metadata(self) await db.commit()
async def ensure_dm(self, user, db=None): if not user.send_id: if not db: db = registry.get('database') user.dm_id = await self._client.open_dm(user.id) await database.__dict__[db.type].user.update_dm_id( db, user.id, user.dm_id) await db.commit()
async def repo_deleted(self, event): slack = registry.get('slack') channel = await slack.channels.get( name=self.config['github']['channel']) msg = SlackMessage(to=channel) msg.text = 'Repository {repo} deleted by {user} :cold_sweat:'.format( repo=event.data['repository']['name'], user=event.data['sender']['login']) await slack.send(msg)
async def release_created(self, event): slack = registry.get('slack') channel = await slack.channels.get( name=self.config['github']['channel']) msg = SlackMessage(to=channel) msg.text = 'Release {release} created in {repo} by {user}'.format( release=event.data['release']['tag_name'], repo=event.data['repository']['name'], user=event.data['sender']['login']) await slack.send(msg)
async def hiring(self): slack = registry.get('slack') channel = await slack.channels.get(name='job_board') message = SlackMessage(to=channel) message.text = self.config['python_jobs']['hiring'] await slack.send(message) message_tips = SlackMessage(to=channel) message_tips.text = self.config['python_jobs']['hiring_tips'] message_tips.thread = message.thread await slack.send(message_tips)
async def _add(self, user, db=None): """ Add an user to the UserManager :param user: users to add """ if not db: db = registry.get('database') await database.__dict__[db.type].user.add(db, user) await db.commit()
async def _delete(self, id_, db=None): """ Delete an user from the UserManager :param id_: id of the user :return: None """ if not db: db = registry.get('database') await database.__dict__[db.type].user.delete(db, id_) await db.commit()
async def _incoming(self, request): data = await request.post() if 'payload' not in data: return Response(text='Invalid', status=400) payload = json.loads(data['payload']) if 'token' not in payload or payload['token'] != self._token: return Response(text='Invalid', status=400) logger.debug('Action handler received: %s', payload) slack = registry.get('slack') settings = self._endpoints.get(payload['callback_id']) if not settings: raise SlackUnknownAction(payload) action = await SlackAction.from_raw(payload, slack, settings=settings) if isinstance(self._save, list) and payload['callback_id'] \ in self._save or self._save is True: logger.debug('Saving incoming action %s from %s', action.callback_id, action.frm.id) db = registry.get('database') await database.__dict__[db.type].dispatcher.save_incoming_action( db, action) await db.commit() coroutine = settings['func'](action, slack) ensure_future(coroutine=coroutine, loop=self._loop, logger=logger) if settings.get('public'): return Response(status=200, body=json.dumps({"response_type": "in_channel"}), content_type='application/json; charset=utf-8') else: return Response(status=200)
async def _delete(self, id_, db=None): """ Delete a channel from the channel store :param id_: id of the channel :return: None """ if not db: db = registry.get('database') await database.__dict__[db.type].channel.delete(db, id_) await db.commit()
def add(self): github = registry.get('github') github.register(self.issues_opened, 'issues', action='opened') github.register(self.issues_closed, 'issues', action='closed') github.register(self.issues_reopened, 'issues', action='reopened') github.register(self.pr_opened, 'pull_request', action='opened') github.register(self.pr_closed, 'pull_request', action='closed') github.register(self.pr_reopened, 'pull_request', action='reopened') github.register(self.release_created, 'release', action='published') github.register(self.repo_created, 'repository', action='created') github.register(self.repo_deleted, 'repository', action='deleted')
async def add(self, user, count=1): db = registry.get('database') await db.execute('''SELECT candy FROM candy WHERE user = ? ''', (user, )) value = await db.fetchone() if value: value = value['candy'] + count else: value = count await db.execute( '''INSERT OR REPLACE INTO candy (user, candy) VALUES (?, ?)''', (user, value)) await db.commit() return value
async def get(self, id_=None, name=None, fetch=False): """ Return a Channel from the Channel Manager :param id_: id of the channel :param name: name of the channel :param update: query the slack api for updated channel info :return: Channel """ if not id_ and not name: raise SyntaxError('id_ or name must be supplied') db = registry.get('database') if name: data = await database.__dict__[db.type].channel.find_by_name(db, name) else: data = await database.__dict__[db.type].channel.find_by_id(db, id_) if data and ( fetch or data['last_update'] < (time.time() - self._refresh)): channel = await self._query_by_id(data['id']) if channel: await self._add(channel, db=db) else: await self._delete(channel, db=db) elif data: channel = Channel( id_=data['id'], raw=json.loads(data['raw']), last_update=data['last_update'] ) else: logger.debug('Channel "%s" not found in the channel store. ' 'Querying the Slack API', (id_ or name)) if id_: channel = await self._query_by_id(id_) else: channel = await self._query_by_name(name) if channel: await self._add(channel, db=db) return channel
async def pypi_search(self, command, slack): response = command.response() pypi = registry.get('pypi') results = await pypi.search(command.text) if not command.text: response.response_type = 'ephemeral' response.text = 'Please enter the package name you wish to find' await slack.send(response) return if results: for result in results[:3]: att = Attachment(title=result['name'], fallback=result['name'], text=result['summary'], title_link='{}/{}'.format( pypi.ROOT_URL, result['name'])) response.attachments.append(att) if len(results) == 4: att = Attachment(title=results[3]['name'], fallback=results[3]['name'], text=results[3]['summary'], title_link='{}/{}'.format( pypi.ROOT_URL, results[3]['name'])) response.attachments.append(att) elif len(results) > 3: path = pypi.SEARCH_PATH.format(command.text) more_info = Attachment( title='{0} more results..'.format(len(results) - 3), fallback='{0} more results..'.format(len(results) - 3), title_link='{}/{}'.format(pypi.ROOT_URL, path)) response.attachments.append(more_info) response.response_type = 'in_channel' response.text = "<@{}> Searched PyPi for `{}`".format( command.frm.id, command.text) else: response.response_type = 'ephemeral' response.text = "Could not find anything on PyPi matching" \ " `{0}`".format(command.text) await slack.send(response)
def add(self): slack = registry.get('slack') slack.add_message('^help', self.help_, flags=re.IGNORECASE, mention=True) slack.add_message( 'tell (<(#|@)(?P<to_id>[A-Z0-9]*)(|.*)?>)' ' (?P<item>.*)', self.publish, flags=re.IGNORECASE, mention=True, admin=True) slack.add_message('hello', self.hello, mention=True, flags=re.IGNORECASE) slack.add_message('hodor', self.hodor, flags=re.IGNORECASE, channel_id='C699LH85A') slack.add_command('/admin', func=self.share_admin) slack.add_message(self.config['candy']['trigger'], self.add_candy_message) slack.add_command('/leaderboard', self.leaderboard) slack.add_event('reaction_added', self.add_candy_reaction) slack.add_command('/do', self.share_digital_ocean) slack.add_action('choose_file', self.choose_file) slack.add_command('/file', self.file) slack.add_command('/gif', self.gif_search) slack.add_action('gif_search', self.gif_search_action) slack.add_event('team_join', self.team_join) slack.add_event('team_join', self.members_joined) slack.add_command('/pypi', self.pypi_search) slack.add_command('/moveto', self.move_to)
async def all(self, fetch=False, deleted=False): """ Retrieve all user of the slack team When fetch is True no dm_id are provided :param fetch: :param deleted: :return: """ db = registry.get('database') if fetch: users = list() fetched_data = await self._client.get_users() for data in fetched_data: user = User(id_=data['id'], raw=data, last_update=time.time(), deleted=data['deleted']) await database.__dict__[db.type].user.add(db, user, dm_id=False) if deleted: users.append(user) elif not deleted and not user.deleted: users.append(user) await db.commit() else: data = await database.__dict__[db.type ].user.get_all(db, deleted=deleted) users = [ User(id_=raw_data['id'], raw=raw_data['raw'], last_update=raw_data['last_update'], dm_id=raw_data['dm_id'], deleted=raw_data['deleted']) for raw_data in data ] return users
async def leaderboard(self, command, slack): response = command.response() candy = registry.get('candy') data = await candy.top(count=10) att = Attachment( title='{} Leaderboard'.format(self.config['candy']['trigger']), fallback='{} Leaderboard'.format(self.config['candy']['trigger']), color='good') if not data: response.text = 'No data to display' else: response.response_type = 'in_channel' for user in data: slack_user = await slack.users.get(user['user']) att.text += '{} *{}*\n'.format(slack_user.name, user['candy']) response.attachments.append(att) await slack.send(response)
async def add_candy_message(self, message, slack, *_): users_raw = self.config['candy']['user_regex'].findall(message.text) users = [ user[2:-1] for user in users_raw if user[2:-1] != message.frm.id ] if not users: return candy = registry.get('candy') response = message.response() count = len(self.config['candy']['trigger_regex'].findall( message.text)) receivers_messages = list() for user in users: slack_user = await slack.users.get(user, dm=True) user_count = await candy.add(user, count) msg = response.clone() msg.to = slack_user text_message = '<@{sender}> gave you {count} {trigger}.' \ ' You now have {user_count} {trigger}.' msg.text = text_message.format( sender=message.frm.id, count=count, trigger=self.config['candy']['trigger'], user_count=user_count) receivers_messages.append(msg) response.to = message.frm response.text = 'You gave {count} {trigger} to <@{user}>'.format( count=count, trigger=self.config['candy']['trigger'], user='******'.join(users)) await slack.send(response) for msg in receivers_messages: await slack.send(msg)
async def get(self, id_, fetch=False, dm=False): """ Return an User from the User Manager If the user doesn't exist query the slack API for it :param id_: id of the user :param dm: Query the direct message channel id :param update: query the slack api for updated user info :return: User """ db = registry.get('database') data = await database.__dict__[db.type].user.find(db, id_) if data and (fetch or data['last_update'] < time.time() - self._refresh): user = await self._query(id_, data['dm_id']) if user: await self._add(user) else: await self._delete(id_, db) elif data: user = User(id_=id_, raw=json.loads(data['raw']), dm_id=data['dm_id'], last_update=data['last_update'], deleted=data['deleted']) else: user = await self._query(id_) if user: await self._add(user) if dm: await self.ensure_dm(user, db) return user