diff --git a/backend/command_parser.py b/backend/command_parser.py index f948ad6..ce06b4b 100644 --- a/backend/command_parser.py +++ b/backend/command_parser.py @@ -1,5 +1,5 @@ from backend import configs -from backend.commands import enter_score, help, group, leaderboard, week_matches, user_stats, group_analysis, matchup_history +from backend.commands import enter_score, help, group, leaderboard, week_matches, user_stats, group_analysis, matchup_history, record from backend.commands.command_message import CommandMessage @@ -48,6 +48,7 @@ def determine_command(lctx, message_object): enter_score, leaderboard, week_matches, + record, user_stats, group_analysis, matchup_history diff --git a/backend/commands/enter_score.py b/backend/commands/enter_score.py index 639a622..abfca25 100644 --- a/backend/commands/enter_score.py +++ b/backend/commands/enter_score.py @@ -1,4 +1,4 @@ -from backend import slack_util, configs, db +from backend import slack_util, configs, db, utility from backend.commands import group BLOCK_NEW_SCORES_MSG = "Sorry, not accepting any scores at this time." @@ -92,7 +92,17 @@ def handle_message(lctx, command_object): slack_util.post_message(lctx, 'Entered into db', lctx.configs[configs.COMMISSIONER_SLACK_ID]) player = db.get_player_by_id(lctx.league_name, users['winner_id']) group_msg = group.build_message_for_group(lctx, player.grouping) - slack_util.post_message(lctx, group_msg, command_object.channel) + rivalry_msg = build_message_for_rivalry_record(lctx, users['winner_id'], users['loser_id']) + slack_util.post_message(lctx, '{}\n{}'.format(rivalry_msg, group_msg), command_object.channel) + + +def build_message_for_rivalry_record(lctx, p1_id, p2_id): + record = utility.get_players_record(lctx, p1_id, p2_id) + p1 = db.get_player_by_id(lctx.league_name, p1_id) + p2 = db.get_player_by_id(lctx.league_name, p2_id) + include_oof = True if abs(record['p1_wins'] - record['p2_wins']) > 5 else False + return '_{} is now {}-{} against {}._{}'.format( + p1.name, record['p1_wins'], record['p2_wins'], p2.name, ' :oof:' if include_oof else '') def parse_first_slack_id(message): diff --git a/backend/commands/help.py b/backend/commands/help.py index 432cd9b..dad118c 100644 --- a/backend/commands/help.py +++ b/backend/commands/help.py @@ -20,6 +20,7 @@ def channel_help(lctx): message = 'In the channel, I support the following:' message = message + '\n`{} me over @them {}` or `{} @them over me {}` - report a score'.format(bot_name, example_score, bot_name, example_score) message = message + '\n`{} group [a, b, c, etc]` - see the current rankings of a group'.format(bot_name) + message = message + '\n`{} record @player1 @player2` - shows the win / loss ratio of player1 vs player2.'.format(bot_name) if lctx.configs[configs.ENABLE_COMMAND_GROUP_ANALYSIS] != 'FALSE': message = message + '\n`{} analyze group [a, b, c, etc]` - see a summary of who can still get promoted and relegated'.format(bot_name) if lctx.configs[configs.ENABLE_COMMAND_LEADERBOARD] != 'FALSE': diff --git a/backend/commands/record.py b/backend/commands/record.py new file mode 100644 index 0000000..930d811 --- /dev/null +++ b/backend/commands/record.py @@ -0,0 +1,61 @@ +from backend import slack_util, configs, db, utility +NO_MATCH_MSG = "I couldn't find a match between you two." + +def handles_message(lctx, command_object): + is_admin = command_object.user == lctx.configs[configs.COMMISSIONER_SLACK_ID] and command_object.is_dm() + if not is_admin and command_object.channel != lctx.configs[configs.COMPETITION_CHANNEL_SLACK_ID]: + return False + if command_object.text.upper().startswith('RECORD') and not is_admin: + return True + return False + + +def get_format_message(lctx): + return 'NA' + + +def handle_message(lctx, command_object): + players = parse_users(command_object) + if players: + if players['first_id'] == players['second_id']: + slack_util.post_message(lctx, 'You are attempting to get the match record between yourself and yourself :bigbrain:', command_object.channel) + return + record = utility.get_players_record(lctx, players['first_id'], players['second_id']) + p1 = db.get_player_by_id(lctx.league_name, players['first_id']) + p2 = db.get_player_by_id(lctx.league_name, players['second_id']) + + if record['p1_wins'] + record['p2_wins'] == 0: + slack_util.post_message(lctx, '{} and {} never played a match together.'.format(p1.name, p2.name), command_object.channel) + return + + if record['p1_wins'] != record['p2_wins']: + better_player = [p1, record['p1_wins']] if record['p1_wins'] > record['p2_wins'] else [p2, record['p2_wins']] + worse_player = [p1, record['p1_wins']] if record['p1_wins'] < record['p2_wins'] else [p2, record['p2_wins']] + slack_util.post_message(lctx, '{} is {}-{} against {}.'.format(better_player[0].name, better_player[1], + worse_player[1], worse_player[0].name), command_object.channel) + else: + slack_util.post_message(lctx, '{} and {} are tied at {} win(s) each.'.format(p1.name, p2.name, record['p1_wins']), command_object.channel) + + + + +def parse_first_slack_id(message): + return message[message.index('<@') + 2: message.index('>')] + + +def parse_second_slack_id(message): + message = message[message.index('>') + 1:] + return parse_first_slack_id(message) + + +def parse_users(command_object): + command = command_object.text + try: + player1 = parse_first_slack_id(command) + player2 = parse_second_slack_id(command) + return { + 'first_id': player1, + 'second_id': player2 + } + except: + return diff --git a/backend/db.py b/backend/db.py index 39853a5..be79cb5 100644 --- a/backend/db.py +++ b/backend/db.py @@ -325,6 +325,15 @@ def get_matches(league_name): return [Match.from_db(m) for m in rows] +def get_matches_between_players(league_name, p1_id, p2_id): + conn = get_connection(league_name) + c = conn.cursor() + c.execute('SELECT rowid, * FROM match WHERE (player_1,player_2) IN ((?, ?),(?, ?))', (p1_id, p2_id, p2_id, p1_id)) + rows = c.fetchall() + conn.close() + + return [Match.from_db(m) for m in rows] + def get_matches_for_season(league_name, season): conn = get_connection(league_name) diff --git a/backend/utility.py b/backend/utility.py index 90b23de..48c037e 100644 --- a/backend/utility.py +++ b/backend/utility.py @@ -48,7 +48,7 @@ def gather_scores(group_matches): return tie_breaker.order_players(players, group_matches) -def print_season_markup(lctx, season = None): +def print_season_markup(lctx, season=None): if season is None: season = db.get_current_season(lctx.league_name) all_matches = db.get_matches_for_season(lctx.league_name, season) @@ -91,7 +91,8 @@ def print_season_markup(lctx, season = None): players = [x for x in players if x['player_id'] is not None] if len(players) > i: p = players[i] - output += get_player_name(all_players, p['player_id']) + ' ' + str(p['m_w']) + '-' + str(p['m_l']) # + ' (' + str(p['s_w']) + '-' + str(p['s_l']) + ')' + output += get_player_name(all_players, p['player_id']) + ' ' + str(p['m_w']) + '-' + str( + p['m_l']) # + ' (' + str(p['s_w']) + '-' + str(p['s_l']) + ')' else: output += ' ' output += '|' @@ -99,10 +100,10 @@ def print_season_markup(lctx, season = None): for grouping in groupings: group_matches = [m for m in all_matches if m.grouping == grouping] - output += '\nh2. Group '+grouping+'\n' + output += '\nh2. Group ' + grouping + '\n' matches_by_week = {} for week in weeks: - output += '||'+str(week) + output += '||' + str(week) matches_by_week[week] = [m for m in group_matches if m.week == week] output += '||\n' @@ -111,7 +112,9 @@ def print_season_markup(lctx, season = None): if i >= len(matches_by_week[week]): break m = matches_by_week[week][i] - output += '|' + get_player_print(all_players, m.player_1_id, m) + '\\\\' + get_player_print(all_players, m.player_2_id, m) + output += '|' + get_player_print(all_players, m.player_1_id, m) + '\\\\' + get_player_print(all_players, + m.player_2_id, + m) output += '|\n' return output @@ -127,5 +130,22 @@ def get_players_dictionary(lctx): def replace_message_variables(lctx, message): message = message.replace('@bot_name', '<@{}>'.format(lctx.configs[configs.BOT_SLACK_USER_ID])) - message = message.replace('#competition_channel', '<#{}>'.format(lctx.configs[configs.COMPETITION_CHANNEL_SLACK_ID])) + message = message.replace('#competition_channel', + '<#{}>'.format(lctx.configs[configs.COMPETITION_CHANNEL_SLACK_ID])) return message + + +def get_players_record(lctx, p1_id, p2_id): + rivalry_matches = db.get_matches_between_players(lctx.league_name, p1_id, p2_id) + p1_wins = 0 + p2_wins = 0 + if len(rivalry_matches) == 0: + return {'p1_wins': 0, 'p2_wins': 0} + + for m in rivalry_matches: + if m.winner_id == p1_id: + p1_wins += 1 + elif m.winner_id == p2_id: + p2_wins += 1 + return {'p1_wins': p1_wins, 'p2_wins': p2_wins} + diff --git a/start_bot.py b/start_bot.py new file mode 100644 index 0000000..0bbd76c --- /dev/null +++ b/start_bot.py @@ -0,0 +1,4 @@ +from backend.leaguebot import LeagueBot + +if __name__ == "__main__": + LeagueBot('StephenLeague').start_bot() \ No newline at end of file diff --git a/tests/commands/test_enter_score.py b/tests/commands/test_enter_score.py index 4266ec7..e06ce09 100644 --- a/tests/commands/test_enter_score.py +++ b/tests/commands/test_enter_score.py @@ -1,10 +1,11 @@ from unittest import TestCase from unittest.mock import patch, call -import datetime, time +import datetime from backend import slack_util, configs, db, match_making from backend.commands import enter_score, group from backend.commands.command_message import CommandMessage +from backend.commands.enter_score import build_message_for_rivalry_record from backend.league_context import LeagueContext from tests import test_league_setup @@ -154,10 +155,11 @@ def test_handle_message_good_entry(self, mock_post_message, mock_add_reaction): self.assertEqual(4, tmp[0].sets) mock_add_reaction.assert_called_once_with(lctx, 'comp_channel', 'any_timestamp', enter_score.WORKED_REACTION) + rivary_msg = build_message_for_rivalry_record(lctx, 'playerA2', 'playerA1') group_msg = group.build_message_for_group(lctx, 'A') calls = [ call(lctx, 'Entered into db', 'commish'), - call(lctx, group_msg, 'comp_channel') + call(lctx, '{}\n{}'.format(rivary_msg, group_msg), 'comp_channel') ] mock_post_message.assert_has_calls(calls) @@ -189,10 +191,11 @@ def test_handle_message_no_sets(self, mock_post_message, mock_add_reaction): self.assertEqual(1, tmp[0].sets) mock_add_reaction.assert_called_once_with(lctx, 'comp_channel', 'any_timestamp', enter_score.WORKED_REACTION) + rivary_msg = build_message_for_rivalry_record(lctx, 'playerA2', 'playerA1') group_msg = group.build_message_for_group(lctx, 'A') calls = [ call(lctx, 'Entered into db', 'commish'), - call(lctx, group_msg, 'comp_channel') + call(lctx, '{}\n{}'.format(rivary_msg, group_msg), 'comp_channel') ] mock_post_message.assert_has_calls(calls) @@ -206,10 +209,11 @@ def test_handle_message_no_sets(self, mock_post_message, mock_add_reaction): self.assertEqual(1, tmp[0].sets) mock_add_reaction.assert_called_once_with(lctx, 'comp_channel', 'any_timestamp', enter_score.WORKED_REACTION) + rivary_msg = build_message_for_rivalry_record(lctx, 'playerA1', 'playerA2') group_msg = group.build_message_for_group(lctx, 'A') calls = [ call(lctx, 'Entered into db', 'commish'), - call(lctx, group_msg, 'comp_channel') + call(lctx, '{}\n{}'.format(rivary_msg, group_msg), 'comp_channel') ] mock_post_message.assert_has_calls(calls) diff --git a/tests/commands/test_record.py b/tests/commands/test_record.py new file mode 100644 index 0000000..e69de29