def handle(message: SlackMessage, bot: SlackAdapter, db: DB): res = bot.client.api_call('users.list') if not res['ok']: raise RuntimeError('call to users.list failed') slack_members = [ member for member in res['members'] if not member['deleted'] ] with db.session_scope() as session: def maybe_create(slack_id): return User.maybe_create_user_from_slack_id( slack_id, bot.client, session) kizuna_members = [ maybe_create(member['id']) for member in slack_members ] for member in kizuna_members: el = [x for x in slack_members if x['id'] == member.slack_id] if not el: continue el = el[0] if member.name != el['name']: member.name = el['name'] bot.reply(message, 'Refreshed users. :^)')
async def handle(message: SlackMessage, bot: SlackAdapter, db: DB): pattern = re.compile('balance', re.IGNORECASE) if not bot.addressed_by(message) or not bot.understands( message, with_pattern=pattern): return with db.session_scope() as session: user = User.get_by_slack_id(session, message.user) balance = user.get_kkred_balance(session) pluralized_kkreds = 'kkred' if balance == 1 else 'kkreds' return bot.reply(message, f'your balance is {balance} {pluralized_kkreds}')
def handle(message: SlackMessage, bot: SlackAdapter, db: DB): pattern = re.compile('react(?:ion) add', re.IGNORECASE) if not bot.addressed_by(message) or not bot.understands( message, with_pattern=pattern): return with db.session_scope() as session: user = User.get_by_slack_id(session, message.user) if not user: return bot.reply(message, no_user_message, ephemeral=True) react_add_image_url = authenticated_path(user, '/react/images/new') return bot.reply(message, react_add_image_url, ephemeral=True)
def handle(message: SlackMessage, bot: SlackAdapter, db: DB): with db.session_scope() as session: user = User.get_by_slack_id(session, message.user) if not user: return bot.reply(message, """ I don't have your user in the db. Prolly run 'kizuna refresh users' and if that still doesn't fix it: Austin f****d up somewhere :^( """.strip(), ephemeral=True) bot.reply(message, build_url(KIZUNA_WEB_URL, '/login', {'auth': user.get_token()}), ephemeral=True)
def test_plugin(capsys): k = Kizuna() k.adapters['slack'] = SlackAdapter(slack_client=FakeSlackClient) k.plugins |= {kizuna.plugins.ping} k.handle('slack', slack_ping_message.copy()) out, err = capsys.readouterr() assert out == '<@UUSERRRRR> pong'
async def handle(message: SlackMessage, bot: SlackAdapter): if message.user == bot.id: return text = message.text.strip() tokens = text.split() if not text: return if bot.mentioned.directly(tokens[0]) and tokens[0].endswith('?'): bot.reply(message, random.choice(im_here_response)) if interrogative_greeting.search(text) and bot.mentioned.anywhere(text): return bot.reply(message, random.choice(interrogative_greeting_response)) if greeting.search(text) and bot.mentioned.anywhere(text): return bot.reply(message, random.choice(greeting_response))
async def handle(message: SlackMessage, bot: SlackAdapter): if not bot.addressed_by(message): return match = bot.understands(message, with_pattern=re.compile('clap (.*)')) try: args = clap_parser.parse_args(match.group(1).split()) except SlackArgumentParserException as err: # lol commented out for max sass # send(str(err)) return bot.respond(message, random_insult()) if args.help: return bot.respond(message, clap_parser.get_help()) if not args.message: return bot.respond(message, random_insult()) new_message = ' {} '.format(args.separator).join(args.message) if args.at: new_message = '{} {}'.format(args.at, new_message) bot.respond(message, new_message)
async def handle(message: SlackMessage, bot: SlackAdapter, db: DB): pattern = "|".join( [".*(?:gibbe|give) money.*", ".*pay me.*", ".*:watermelon:.*"]) trigger = re.compile(pattern, re.IGNORECASE) message_ts = arrow.get(message.ts) if not is_payable(message_ts): return user_id = message.user with db.session_scope() as session: user = User.get_by_slack_id(session, user_id) if not user: return latest_mine = session \ .query(KKredsTransaction) \ .filter(KKredsTransaction.to_user_id == user.id) \ .filter(KKredsTransaction.is_mined) \ .order_by(KKredsTransaction.created_at.desc()) \ .first() if latest_mine and latest_mine.created_at: message_ts_stripped = strip_date(message_ts) latest_mine_time_stripped = strip_date(latest_mine.created_at) if latest_mine_time_stripped >= message_ts_stripped: return kizuna_user = User.get_by_slack_id(session, bot.id) mined_kkred = KKredsTransaction(from_user=kizuna_user, to_user=user, amount=1, is_mined=True, created_at=message_ts.datetime) session.add(mined_kkred) bot.reply(message, 'successfully mined 1 kkred')
def respond(message: SlackMessage, bot: SlackAdapter, db: DB): if not bot.addressed_by(message): return matches = bot.understands(message, with_pattern=re.compile( 'tfw (.*)', re.IGNORECASE)) if not matches: return query = matches.group(1).strip() with db.session_scope() as session: user = User.get_by_slack_id(session, message.user) if not user: return bot.reply(message, no_user_message, ephemeral=True) react_homepage_url = authenticated_path(user, '/react') react_add_image_url = authenticated_path(user, '/react/images/new') # kizuna react <tag> def add_images_nag(): add_images = format_url('(Add Images)', react_add_image_url) view_images = format_url('(View Images)', react_homepage_url) bot.reply( message, f"You can add some images though! {add_images} {view_images}", ephemeral=True) possible_tags = [token.strip().lower() for token in query.split()] tags = (session.query(ReactionImageTag).options( orm.joinedload("images")).filter( ReactionImageTag.name.in_(possible_tags)).all()) if tags: images = list( itertools.chain.from_iterable([tag.images for tag in tags])) if len(images) > 0: for image in images: image.tags_text = [ tag.name for tag in image.tags if tag.name in possible_tags ] images.sort(key=lambda t: len(t.tags_text), reverse=True) best_match_length = len(images[0].tags_text) best_matches = [ image for image in images if len(image.tags_text) == best_match_length ] return bot.respond(message, choice(best_matches).url) return [ bot.respond( message, f"I don't have any images for \"{query}\" :^("), add_images_nag() ] return [ bot.respond(message, f"I don't have anything for \"{query}\" :^("), add_images_nag() ]
rabbitmq_broker = RabbitmqBroker(url=config.RABBITMQ_URL) dramatiq.set_broker(rabbitmq_broker) if not config.SLACK_API_TOKEN: raise ValueError( 'You are missing a slack token! Please set the SLACK_API_TOKEN environment variable in your ' '.env file or in the system environment') sc = SlackClient(config.SLACK_API_TOKEN) db_engine = create_engine(config.DATABASE_URL) make_session = sessionmaker(bind=db_engine) k = Kizuna() k.adapters['slack'] = SlackAdapter(slack_client=sc) k.skills |= { DB(make_session=make_session), } k.plugins |= { kizuna.plugins.chat, kizuna.plugins.clap, kizuna.plugins.ping, kizuna.plugins.kkreds } @dramatiq.actor def slack_worker(payload): logging.debug(payload) k.handle('slack', payload)
async def handle(message: SlackMessage, bot: SlackAdapter): if bot.addressed_by(message) and bot.understands( message, with_pattern=re.compile('ping$', re.I)): bot.reply(message, 'pong')
async def handle(message: SlackMessage, bot: SlackAdapter, db: DB): pattern = re.compile("(?:pay|tip|give|send)\s+(\S*)\s+(\S*)", re.IGNORECASE) if not bot.addressed_by(message): return matches = bot.understands(message, with_pattern=pattern) if not matches: return message_ts = arrow.get(message.ts) sending_user_id = message.user with db.session_scope() as session: sending_user = User.get_by_slack_id(session, sending_user_id) if not sending_user: return receiving_user_raw = matches[0] if not is_user_mention(receiving_user_raw): return bot.reply( message, 'User has to be an `@` mention. Like it has to be a real blue `@` mention.' ) receiving_user = User.get_by_slack_id( session, extract_user_id_from_mention(receiving_user_raw)) if not receiving_user: return bot.reply(message, 'Could not find that user') if sending_user.id == receiving_user.id: return bot.reply(message, 'You can’t send money to yourself.') amount_raw = matches[1] try: amount = Decimal(amount_raw) except InvalidOperation: return bot.reply( message, 'That amount is invalid. Try a decimal or integer value') if amount <= 0: return bot.reply(message, 'Amount has to be non-zero') if amount > sending_user.get_kkred_balance(session): return bot.reply(message, 'You don’t have enough kkreds') transaction = KKredsTransaction(from_user=sending_user, to_user=receiving_user, amount=amount, created_at=message_ts.datetime) session.add(transaction) bot.reply(message, f'successfully sent {amount} to {receiving_user.name}')
def handle(message: SlackMessage, bot: SlackAdapter, db: DB): if not bot.addressed_by(message): return matches = bot.understands(message, with_pattern=re.compile('mentions(?: (.*))?', re.I)) if not matches: return user_args = matches.group(1).split() if matches. else [] try: args = parser.parse_args(user_args) except SlackArgumentParserException as err: return send(str(err)) user_layout = args.layout output_format = 'png' if args.raster else 'pdf' def send_message(text): return slack_client.api_call("chat.postMessage", channel=channel, text=text, as_user=True) if user_layout not in self.available_layouts: layout_error_message = ("Oops! --user_layout needs to be one of '{}'. " "You gave me '{}'").format(', '.join(self.available_layouts), user_layout) return send_message(layout_error_message) if args.help: return send_message(self.help_text) with self.db_session_scope() as session: edges = session.query(AtGraphEdge).order_by(AtGraphEdge.weight.asc()).all() users = session.query(User).order_by(User.name.asc()).all() if not edges or len(edges) < 1: send_message("Uhh...Could not find any edges in the db. Something is probably wrong.") return loading_message = slack_client.api_call("chat.postMessage", channel=channel, text=WAIT_A_SEC + JAP_DOT, as_user=True) loaded = False def continiously_update_loading_message(): cycle_count = 0 dot_count = 1 while not loaded and cycle_count < 20: sleep(1) if loaded: break dot_count = dot_count + 1 if dot_count < 3 else 1 new_text = WAIT_A_SEC + (dot_count * JAP_DOT) slack_client.api_call("chat.update", ts=loading_message['ts'], channel=channel, text=new_text, as_user=True) cycle_count += 1 thread = Thread(target=continiously_update_loading_message) if loading_message['ok']: thread.start() graph = Digraph(comment='Mentions', format=output_format) color_index = 0 user_color_map = {} colors = tableau.get_map('Tableau_20').hex_colors for user in users: color = colors[color_index] color_index = color_index + 1 if color_index < (len(colors) - 1) else 0 user_color_map[user.name] = color graph.node(user.name, color=color) max_weight = edges[len(edges) - 1].weight min_weight = edges[0].weight max_penwidth = 5 min_penwidth = 0.10 max_fontsize = 20 min_fontsize = 7 def scale_penwidth_by(value): return self.linear_scale(max_weight, min_weight, max_penwidth, min_penwidth, value) def scale_fontsize_by(value): return self.linear_scale(max_weight, min_weight, max_fontsize, min_fontsize, value) for edge in edges: graph.edge(edge.head_user.name, edge.tail_user.name, penwidth=str(scale_penwidth_by(edge.weight)), label=str(edge.weight), weight=str(edge.weight), fontsize=str(scale_fontsize_by(edge.weight)), fontcolor=str(user_color_map[edge.head_user.name]), color=user_color_map[edge.head_user.name]) def dot(): graph.engine = 'dot' def neato(): graph.engine = 'neato' def fdp(): graph.engine = 'fdp' def twopi(): graph.engine = 'twopi' def circo(): graph.engine = 'circo' def layout_graph(layout): return { "dot": dot, "neato": neato, "fdp": fdp, "twopi": twopi, "circo": circo }.get(layout, dot) try: layout_graph(user_layout)() slack_client.api_call('files.upload', as_user=True, channels=message['channel'], filename=f'graph.{output_format}', file=graph.pipe()) except CalledProcessError as err: send_message('Encountered a problem while rendering the graph :monkas:') raise err except TypeError as err: send_message('Encountered a problem while trying to write the graph to the file system :monkas:') raise err finally: loaded = True thread.join() slack_client.api_call("chat.delete", ts=loading_message['ts'], channel=channel, as_user=True)