async def update_attendance_task(self): scope = [ 'https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive' ] creds = ServiceAccountCredentials.from_json_keyfile_name( defs.dir_path + '/client_secret.json', scope) client = gspread.authorize(creds) sheet = client.open("Hive Mind Giga-Sheet").worksheet( 'Assessment Sheet') participants = get_participants() to_update = [] col = raiders.get_col('attendance') for name in participants: attendance = round(participants[name]['attendance'] * 100) sheet_attendance = raiders.getRaiderAttribute(name, 'attendance') try: sheet_attendance = float(sheet_attendance.replace('%', '')) except ValueError: sheet_attendance = None if attendance != sheet_attendance: row = raiders.getRaiderAttribute(name, 'row') val = float(attendance) / 100 to_update.append({'row': row, 'val': val}) if len(to_update) > 0: min_row = min([u['row'] for u in to_update]) max_row = max([u['row'] for u in to_update]) first = gspread.utils.rowcol_to_a1(min_row, col) last = gspread.utils.rowcol_to_a1(max_row, col) cells = sheet.range('{}:{}'.format(first, last)) for update in to_update: row = update['row'] - min_row cells[row].value = update['val'] sheet.update_cells(cells) logger.log_event( 'attendance_update', 'update_attendance task finished with {} updates.'.format( len(to_update)))
def get_message_brief(categories): message = 'Attendance:\n' prev_type = '' for category in categories: if category['type'] is 'class': if prev_type is 'player': message += '\n' message += '__**{}:**__\n'.format(category['title']) for name, player_attendance in category['attendance']: if raiders.getRaiderAttribute(name, 'team') == 'team red': message += ':red_circle:' if raiders.getRaiderAttribute(name, 'team') == 'team blue': message += ':blue_circle:' if category['type'] is 'player': message += '__**{}**__ - '.format(name.capitalize()) else: message += '**{}** - '.format(name.capitalize()) raids = player_attendance['raids'] attended_raids = sum( [len(raids[raid]['raids']) for raid in raids.keys()]) if (attended_raids == 0): message += 'no raids registered.\n' else: attendance = round(player_attendance['attendance'] * 100) missed_raids = sum([ len(raids[raid]['missed_raids']) for raid in raids.keys() ]) signed_raids = sum([ len(raids[raid]['signed_raids']) for raid in raids.keys() ]) message += 'attendance: **{}%**, attended raids: **{}**, signed off: **{}**, didn\'t sign off: **{}**\n'.format( attendance, attended_raids, signed_raids, missed_raids) if category['type'] is 'class': message += '\n' prev_type = category['type'] return message
def get_fight_summary(fight, metrics, report_info): summary = { 'fight': fight, 'parses': {}, 'report': { 'title': report_info['title'], 'id': report_info['id'], 'start': report_info['start'] } } for metric in metrics: url_dps = 'https://classic.warcraftlogs.com/reports/' + report_info[ 'id'] + '#fight=' + str( fight['id']) + '&view=rankings&playermetric=' + metric chrome_options = Options() chrome_options.add_argument('--headless') chrome_options.add_experimental_option('excludeSwitches', ['enable-logging']) print(defs.timestamp(), '*' + url_dps) driver = webdriver.Chrome(options=chrome_options) driver.get(url_dps) element = WebDriverWait(driver, 60).until( EC.presence_of_element_located((By.CLASS_NAME, "primary"))) fight['deaths'] = element.text element = WebDriverWait(driver, 60).until( EC.presence_of_element_located((By.CLASS_NAME, "player-table"))) row_elements = element.find_elements_by_tag_name('tr')[1:] for row_element in row_elements: row_stats = {} cell_elements = row_element.find_elements_by_tag_name('td') name = cell_elements[4].find_element_by_tag_name( 'a').get_attribute('innerHTML').lower() role = raiders.getRaiderAttribute(name, 'role') if ((metric == 'dps' and role in ['melee', 'ranged']) or (metric == 'hps' and role == 'healer')): row_stats['percentile'] = int(cell_elements[0].text) row_stats['rank'] = cell_elements[1].text row_stats['out_of'] = int(cell_elements[2].text.replace( ',', '')) row_stats['best_rank'] = cell_elements[3].text row_stats['dps'] = float(cell_elements[5].text.replace( ',', '')) row_stats['ilvl'] = int(cell_elements[6].text) row_stats['ipercentile'] = int(cell_elements[7].text) summary['parses'][name] = row_stats driver.close() driver.quit() return summary
async def signoffs(self, ctx, *args): logger.log_command(ctx, args) try: await ctx.message.delete() except: pass if len(args) is 1: query_date = get_date_from_string(args[0]) elif len(args) is 0: query_date = datetime.combine(date.today(), time()) else: await ctx.send( 'This command takes at most one argument: the date. Use \'!help {}\' for help on how to use this command.' .format(ctx.command.name)) return epoch = datetime(1970, 1, 1) timestamp = int((query_date - epoch).total_seconds() * 1000) signoffs = schedule_file.get('signoffs', on_error=[]) names = [ so['name'].lower().capitalize() for so in signoffs if so['start'] <= timestamp <= so['end'] ] message = 'Sign offs: ' + ', '.join(names) + '\n' roles_so = {} for name in names: role = raiders.getRaiderAttribute(name, 'role') roles_so[role] = roles_so.get(role, 0) + 1 all_raiders = raiders.getRaiders() roles_at = {} for raider in all_raiders: if not raider.capitalize() in names: role = all_raiders[raider]['role'] roles_at[role] = roles_at.get(role, 0) + 1 roles = [ '{}: {}'.format(role.capitalize(), roles_so[role]) for role in roles_so ] message += 'Signed off ({}): '.format(sum( roles_so.values())) + ', '.join(roles) + '\n' roles = [ '{}: {}'.format(role.capitalize(), roles_at[role]) for role in roles_at ] message += 'Attending ({}): '.format(sum( roles_at.values())) + ', '.join(roles) await ctx.send(message)
def make_attendance_plot(participants, figurename): attendances = [] for p in participants: attended_raids = len(participants[p]['raids']) missed_raids = len(participants[p]['missed_raids']) attendance = attended_raids / (attended_raids + missed_raids) attendances.append([p, attendance]) attendances.sort(key=lambda x: x[1], reverse=True) names = [entry[0] for entry in attendances] attendances = [entry[1] * 100 for entry in attendances] cols = [ defs.colors[raiders.getRaiderAttribute(name, 'class')] for name in names ] y_pos = np.arange(len(names)) names = [ '{} ({}%)'.format(name, round(attendances[i], 1)) for i, name in enumerate(names) ] _, ax = plt.subplots(figsize=(20, 15)) ax.barh(y_pos, attendances, color=cols, edgecolor='white', linestyle='-', linewidth=0) ax.set_yticks(y_pos) ax.set_yticklabels(names) ax.invert_yaxis() # labels read top-to-bottom ax.set_xlabel('Attendance [%]', color='white') plt.savefig(defs.dir_path + '/' + figurename)
async def cmd_attendance(self, ctx, *args): logger.log_command(ctx, args) await ctx.message.delete() args = list(args) options, args = defs.get_options(args) days = None months = None digits = [i for i, arg in enumerate(args) if arg.isdigit()] if len(digits) > 1: await ctx.send( 'Arguments \'{}\' not understood. Please use \'!help {}\' for help on how to use this command.' .format(args, ctx.command.name), delete_after=self.error_messages_lifetime) return if (len(args) - 1) in digits: months = int(args[-1]) args = args[:-1] if (len(args) - 2) in digits: last_arg = args[-1].lower() if last_arg in ['day', 'days']: days = int(args[-2]) args = args[:-2] elif last_arg in ['month', 'months']: months = int(args[-2]) args = args[:-2] else: await ctx.send( 'Argument \'{}\' not understood. Please use \'!help {}\' for help on how to use this command.' .format(args[-1], ctx.command.name), delete_after=self.error_messages_lifetime) return team = '' if ('-r' in options): team = 'team red' if ('-b' in options): team = 'team blue' categories = [] for arg in args: if (arg.lower()[-1] is 's') and (arg.lower()[:-1] in defs.classes): arg = arg.lower()[:-1] if arg.lower() in defs.classes: class_raiders = raiders.all_with_attribute( 'class', arg.lower()) class_names = [ raider for raider in class_raiders if raiders.getRaiderAttribute(raider, 'team') == team or team == '' ] category = { 'type': 'class', 'title': arg.capitalize() + 's', 'attendance': class_names } else: category = {'type': 'player', 'attendance': [arg]} categories.append(category) for category in categories: category['attendance'] = [(name, get_participant(name.capitalize(), days=days, months=months)) for name in category['attendance']] category['attendance'].sort(key=lambda x: len(x[1]['raids']), reverse=True) category['attendance'].sort(key=lambda x: x[1]['attendance'], reverse=True) message = get_message_brief(categories) await ctx.send(message)
def get_participants(update_attendance=True, days=None, months=None): attendance = get_attendance(update_attendance, days, months) participants = {} # Count attendance for report in attendance: for participant in report['participants']: team = raiders.getRaiderAttribute(participant, 'team') if team == report['team']: participants.setdefault(participant, {}) for raidname in report['raids']: participants[participant].setdefault( raidname, {'raids': []}) participants[participant][raidname]['raids'].append( report['start']) for name in participants: for raid in participants[name]: participants[name][raid]['first_raid'] = min( participants[name][raid]['raids']) # Count absence for name in participants: for raid_name in participants[name]: missed_raids = [] signed_raids = [] reports = [ report for report in attendance if raid_name in report['raids'] ] for report in reports: start = report['start'] if not start in participants[name][raid_name]['raids']: if start > participants[name][raid_name]['first_raid']: if (schedule.has_signed_off(name, start)): signed_raids.append(start) else: missed_raids.append(start) participants[name][raid_name]['missed_raids'] = missed_raids participants[name][raid_name]['signed_raids'] = signed_raids result = {} for name in participants: total_attended = 0 total_missed = 0 total_signed = 0 for raid in participants[name]: raid_info = participants[name][raid] total_attended += len(raid_info['raids']) total_missed += len(raid_info['missed_raids']) total_signed += len(raid_info['signed_raids']) try: raid_info['attendance'] = len(raid_info['raids']) / ( len(raid_info['raids']) + len(raid_info['missed_raids']) + len(raid_info['signed_raids'])) except ZeroDivisionError: raid_info['attendance'] = -1 try: raid_info['sign_rate'] = len(raid_info['signed_raids']) / (len( raid_info['signed_raids'])) except ZeroDivisionError: raid_info['sign_rate'] = 1 try: att = total_attended / (total_attended + total_missed + total_signed) except ZeroDivisionError: att = -1 try: sr = total_signed / (total_missed + total_signed) except ZeroDivisionError: sr = 1 result[name] = { 'attendance': att, 'sign_rate': sr, 'raids': participants[name] } return result
def plot_fight(f, image_path): fight = f['fight'] parses = f['parses'] melee_parses = [] ranged_parses = [] healer_parses = [] for name in parses: if (raiders.getRaiderAttribute(name, 'role') == 'ranged'): ranged_parses.append(name) elif (raiders.getRaiderAttribute(name, 'role') == 'melee'): melee_parses.append(name) elif (raiders.getRaiderAttribute(name, 'role') == 'healer'): healer_parses.append(name) group_names = ['Melee', 'Ranged', 'Healers'] metric = ['DPS', 'DPS', 'HPS'] tables = "" for i, current_parses in enumerate( [melee_parses, ranged_parses, healer_parses]): rows = "" for j, name in enumerate(current_parses[:3]): parse = parses[name] percentile = parse['percentile'] class_color = defs.colors[raiders.getRaiderAttribute( name, 'class')] rows += ranking_html_factory.get_row( number=str(j + 1), name=name.capitalize(), name_color=class_color, parse=str(percentile), parse_color=defs.getParseColor(percentile), rank=parse['rank'], dps=str(parse['dps']), ) avg_parse = 0 avg_rank = 0 avg_dps = 0 n = len(current_parses) for name in current_parses: avg_parse += parses[name]['percentile'] / n avg_rank += int(parses[name]['rank'].replace('~', '')) / n avg_dps += parses[name]['dps'] / n avg_parse = round(avg_parse, 1) avg_rank = int(avg_rank) avg_dps = round(avg_dps, 1) tables += ranking_html_factory.get_table( group_name=group_names[i], metric=metric[i], rows=rows, avg_parse=str(avg_parse), avg_parse_color=defs.getParseColor(avg_parse), avg_rank=str(avg_rank), avg_dps=str(avg_dps)) html = ranking_html_factory.get_html(fight['name'], tables) html_path = defs.dir_path + '/boss_summaries/' + fight['name'] + '.html' with open(html_path, 'w') as file: file.write(html) chrome_options = Options() chrome_options.add_argument('--headless') chrome_options.add_experimental_option('excludeSwitches', ['enable-logging']) driver = webdriver.Chrome(options=chrome_options) driver.get('file:///' + html_path) body = driver.find_element_by_tag_name('body') size = body.size driver.set_window_size(size['width'], size['height']) driver.save_screenshot(image_path) driver.close() driver.quit()