def test_get_member_history_quit_and_rejoin(): date = datetime(2019, 2, 12, 7, 32, 1, 0) date2 = datetime(2019, 2, 12, 7, 32, 2, 0) timestamp = datetime.timestamp(date) timestamp2 = datetime.timestamp(date2) members = __fake_members__.copy() del members[2] h = history.get_member_history(members, date, __fake_history__, None) h2 = history.get_member_history(__fake_members__, date2, h, None) h_member = h['members'][__fake_members__[2].tag] h2_member = h2['members'][__fake_members__[2].tag] assert h_member['status'] == 'absent' assert h_member['events'][1]['event'] == 'quit' assert h_member['events'][1]['type'] == 'left' assert h_member['events'][1]['date'] == timestamp assert h2_member['status'] == 'present' assert h2_member['events'][1]['event'] == 'quit' assert h2_member['events'][1]['type'] == 'left' assert h2_member['events'][1]['date'] == timestamp assert h2_member['events'][2]['event'] == 'join' assert h2_member['events'][2]['type'] == 're-join' assert h2_member['events'][2]['date'] == timestamp2
def test_get_member_history_donations_reset(): date = datetime(2019, 2, 12, 7, 32, 1, 0) timestamp = datetime.timestamp(date) members_copy = copy.deepcopy(__fake_members__) members_copy[0].donations = 5 h = history.get_member_history(__fake_members__, date, __fake_history__, None) h2 = history.get_member_history(members_copy, date, h, None) members = h2['members'] assert members[__fake_members__[0].tag]['donations'] == 5 assert members[__fake_members__[0].tag]['donations_last_week'] == __fake_members__[0].donations
def test_get_member_history_unchanged(): """ Getting history twice. Nothing should be changed except the timestamp """ date = datetime(2019, 2, 12, 7, 32, 1, 0) date2 = datetime(2019, 2, 12, 7, 32, 2, 0) timestamp = datetime.timestamp(date) timestamp2 = datetime.timestamp(date2) h = history.get_member_history(__fake_members__, date, None, None) h2 = history.get_member_history(__fake_members__, date2, h, None) assert h['last_update'] == timestamp assert h2['last_update'] == timestamp2 assert h['members'] == h2['members']
def test_get_member_history_role_change(): date = datetime(2019, 2, 12, 7, 32, 1, 0) timestamp = datetime.timestamp(date) h = history.get_member_history(__fake_members__, __fake_history__, None, date) members = h['members'] assert h['last_update'] == timestamp assert members[__fake_members__[1]['tag']]['status'] == 'present' assert members[__fake_members__[1] ['tag']]['events'][1]['event'] == 'role change' assert members[__fake_members__[1] ['tag']]['events'][1]['type'] == 'demotion' assert members[__fake_members__[1] ['tag']]['events'][1]['role'] == __fake_members__[1]['role'] assert members[__fake_members__[1] ['tag']]['events'][1]['date'] == timestamp assert members[__fake_members__[2]['tag']]['status'] == 'present' assert members[__fake_members__[2] ['tag']]['events'][1]['event'] == 'role change' assert members[__fake_members__[2] ['tag']]['events'][1]['type'] == 'promotion' assert members[__fake_members__[2] ['tag']]['events'][1]['role'] == __fake_members__[2]['role'] assert members[__fake_members__[2] ['tag']]['events'][1]['date'] == timestamp
def test_war_participation_activity_update(): date = datetime(2019, 2, 12, 7, 32, 1, 0) h = history.get_member_history(__fake_members__, __fake_history__, __fake_currentwar__, date) h_member = h['members'][__fake_members__[0].tag] assert h_member['last_activity_date'] == datetime.timestamp(date)
def test_get_member_history_new(): date = datetime(2019, 2, 12, 7, 32, 0, 0) timestamp = datetime.timestamp(date) h = history.get_member_history(__fake_members__, date, None, None) assert h['last_update'] == timestamp for member in __fake_members__: assert h['members'][member.tag]['role'] == member.role assert h['members'][member.tag]['status'] == 'present' assert h['members'][member.tag]['events'][0]['event'] == 'join' assert h['members'][member.tag]['events'][0]['type'] == 'new' assert h['members'][member.tag]['events'][0]['role'] == member.role assert h['members'][member.tag]['events'][0]['date'] == 0
def test_process_absent_members(tmpdir): config_file = tmpdir.mkdir('test_get_suggestions').join('testfile') config_file.write(__config_file_score__ + '\nthreshold_demote=-999999\nthreshold_promote=9999999') config = load_config_file(config_file.realpath()) h = history.get_member_history(__fake_clan__['member_list'], __fake_history_old_member__) absent_members = crtools.process_absent_members(config, h['members']) assert len(absent_members) == 1 assert absent_members[0]['tag'] == '#ZZZZZZ'
def test_get_suggestions_kick(tmpdir): config_file = tmpdir.mkdir('test_get_suggestions').join('testfile') config_file.write(__config_file_score__ + '\nmin_clan_size=1') config = load_config_file(config_file.realpath()) h = history.get_member_history(__fake_clan__['member_list'], None) members = crtools.process_members(config, __fake_clan__, __fake_warlog__, {"state": "notInWar"}, h) suggestions = crtools.get_suggestions(config, members, __fake_clan__) print(suggestions) assert suggestions[0].startswith('Kick') assert members[3]['name'] in suggestions[0]
def test_get_suggestions_recruit(tmpdir): config_file = tmpdir.mkdir('test_get_suggestions').join('testfile') config_file.write(__config_file_score__ + '\nthreshold_demote=-999999\nthreshold_promote=9999999') config = load_config_file(config_file.realpath()) h = history.get_member_history(__fake_clan__['member_list'], None) members = crtools.process_members(config, __fake_clan__, __fake_warlog__, {"state": "notInWar"}, h) suggestions = crtools.get_suggestions(config, members, __fake_clan__) print(suggestions) assert len(suggestions) == 1 assert suggestions[0] == config['strings']['suggestionRecruit']
def test_get_suggestions_kick(tmpdir): config_file = tmpdir.mkdir('test_get_suggestions').join('testfile') config_file.write(__config_file_score__ + '\nmin_clan_size=1') config = load_config_file(config_file.realpath()) h = history.get_member_history(__fake_clan__.member_list, None) members = crtools.process_members(config, __fake_clan__, __fake_warlog__, __fake_currentwar_notinwar__, h) suggestions = crtools.get_suggestions(config, members, __fake_clan__.required_trophies) print(suggestions) assert suggestions[0].startswith('Kick') assert members[3].name in suggestions[0]
def test_get_suggestions_promote_demote(tmpdir): config_file = tmpdir.mkdir('test_get_suggestions').join('testfile') config_file.write(__config_file_score__ + '\nthreshold_promote=10') config = load_config_file(config_file.realpath()) h = history.get_member_history(__fake_clan__['member_list'], None) members = crtools.process_members(config, __fake_clan__, __fake_warlog__, {"state": "notInWar"}, h) suggestions = crtools.get_suggestions(config, members, __fake_clan__) print(suggestions) assert suggestions[0].startswith('Demote') assert members[2]['name'] in suggestions[0] assert suggestions[1].startswith('Promote') or suggestions[2].startswith( 'Promote') assert members[4]['name'] in suggestions[1] or members[4][ 'name'] in suggestions[2]
def test_get_suggestions_promote_demote(tmpdir): config_file = tmpdir.mkdir('test_get_suggestions').join('testfile') config_file.write(__config_file_score__ + '\nthreshold_promote=10') config = load_config_file(config_file.realpath()) h = history.get_member_history(__fake_clan__.member_list, None) members = crtools.process_members(config, __fake_clan__, __fake_warlog__, __fake_currentwar_notinwar__, h) suggestions = crtools.get_suggestions(config, members, __fake_clan__.required_trophies) print(suggestions) assert suggestions[0].startswith('Demote') assert members[2].name in suggestions[0] assert suggestions[1].startswith('Promote') or suggestions[2].startswith( 'Promote') assert members[4].name in suggestions[1] or members[4].name in suggestions[ 2]
def test_donations_score(tmpdir): config_file = tmpdir.mkdir('test_donations_score').join('testfile') config_file.write(__config_file_score__) config = load_config_file(config_file.realpath()) calc = ScoreCalculator(config) war = ProcessedCurrentWar( config=config, current_war=pyroyale.WarCurrent(state='notInWar')) member_history = history.get_member_history(__fake_member_list__, config['crtools']['timestamp'], '{}', war) date = datetime(2019, 2, 12, 7, 32, 1, 0) member_6 = MemberFactory(config=config, current_war=war, clan=__fake_clan__, member_history=member_history, warlog=pyroyale.WarLog(items=[]), days_from_donation_reset=6).get_processed_member( __fake_member_list__[0]) member_3 = MemberFactory(config=config, current_war=war, clan=__fake_clan__, member_history=member_history, warlog=pyroyale.WarLog(items=[]), days_from_donation_reset=3).get_processed_member( __fake_member_list__[0]) member_0 = MemberFactory(config=config, current_war=war, clan=__fake_clan__, member_history=member_history, warlog=pyroyale.WarLog(items=[]), days_from_donation_reset=0).get_processed_member( __fake_member_list__[0]) assert calc.get_member_donations_score(member_6) == 11 assert calc.get_member_donations_score(member_3) == 18 assert calc.get_member_donations_score(member_0) == 31
def test_donations_score(tmpdir): config_file = tmpdir.mkdir('test_donations_score').join('testfile') config_file.write(__config_file_score__) config = load_config_file(config_file.realpath()) date = datetime(2019, 2, 12, 7, 32, 1, 0) timestamp = datetime.timestamp(date) members = history.get_member_history(__fake_clan__['member_list'], __fake_history__, None, date)["members"] member_tag_0 = __fake_clan__['member_list'][0]['tag'] member_6 = crtools.enrich_member_with_history( config, __fake_clan__['member_list'][0], members, 6, date) member_3 = crtools.enrich_member_with_history( config, __fake_clan__['member_list'][0], members, 3, date) member_0 = crtools.enrich_member_with_history( config, __fake_clan__['member_list'][0], members, 0, date) assert crtools.donations_score(config, member_6) == 11 assert crtools.donations_score(config, member_3) == 18 assert crtools.donations_score(config, member_0) == 31
def test_get_suggestions_nosuggestions(tmpdir): config_file = tmpdir.mkdir('test_get_suggestions').join('testfile') config_file.write( __config_file_score__ + '\nthreshold_demote=-999999\nthreshold_promote=9999999\nmin_clan_size={}' .format(crtools.MAX_CLAN_SIZE)) config = load_config_file(config_file.realpath()) war = ProcessedCurrentWar( config=config, current_war=pyroyale.WarCurrent(state='notInWar')) factory = MemberFactory(config=config, member_history=history.get_member_history( __fake_clan__.member_list, config['crtools']['timestamp'], '{}', war), current_war=war, clan=__fake_clan__, warlog=pyroyale.WarLog(items=[])) members = [] for i in range(0, crtools.MAX_CLAN_SIZE): member = factory.get_processed_member( pyroyale.ClanMember(tag="#AAAAAA", name="LeaderPerson", role="leader", exp_level=13, trophies=9999, donations=9999, arena=pyroyale.Arena(id=54000012, name='Legendary Arena'), last_seen="20190802T154619.000Z")) member.safe = True members.append(member) suggestions = crtools.get_suggestions(config, members, __fake_clan__.required_trophies) assert len(suggestions) == 1 assert suggestions[-1] == config['strings']['suggestionNone']
def build_dashboard(config): # pragma: no coverage """Compile and render clan dashboard.""" print('- requesting info for clan id: {}'.format(config['api']['clan_id'])) clan, warlog, current_war = get_data_from_api(config) # Create temporary directory. All file writes, until the very end, # will happen in this directory, so that no matter what we do, it # won't hose existing stuff. tempdir = tempfile.mkdtemp(config['paths']['temp_dir_name']) # Putting everything in a `try`...`finally` to ensure `tempdir` is removed # when we're done. We don't want to pollute the user's disk. try: output_path = os.path.expanduser(config['paths']['out']) # process data from API current_war_processed = ProcessedCurrentWar(current_war, config) clan_processed = ProcessedClan(clan, current_war_processed, config) member_history = history.get_member_history( clan.member_list, config['crtools']['timestamp'], io.get_previous_history(output_path), current_war_processed) members_processed = process_members(config, clan, warlog, current_war_processed, member_history) recent_wars = process_recent_wars(config, warlog) former_members = process_absent_members(config, member_history['members']) io.parse_templates( config, member_history, tempdir, clan_processed, members_processed, former_members, current_war_processed, recent_wars, get_suggestions(config, members_processed, clan_processed.required_trophies), get_scoring_rules(config)) if (config['crtools']['debug'] == True): # archive outputs of API for debugging io.dump_debug_logs( tempdir, { 'clan': clan.to_dict(), 'warlog': warlog.to_dict(), 'current_war': current_war.to_dict(), 'clan-processed': clan_processed, 'members-processed': members_processed, 'current_war-processed': current_war_processed, 'recentwars-processed': list(map(lambda war: war.to_dict(), recent_wars)) }) # if fankit is previously downloaded, it will copy fankit. Otherwise, # if fankit is enabled, it will download it. fankit.get_fankit(tempdir, output_path, config['paths']['use_fankit']) io.copy_static_assets(tempdir, config['paths']['clan_logo'], config['paths']['favicon']) io.move_temp_to_output_dir(tempdir, output_path) discord.trigger_webhooks(config, current_war, members_processed) except Exception as e: logger.error('error: {}'.format(e)) finally: # Ensure that temporary directory gets deleted no matter what shutil.rmtree(tempdir)
def build_dashboard(config): # pragma: no coverage """Compile and render clan dashboard.""" logger.debug('crtools version v{}'.format(__version__)) logger.debug('pyroyale version v{}'.format(pyroyale.__version__)) logger.debug(config) # Create temporary directory. All file writes, until the very end, # will happen in this directory, so that no matter what we do, it # won't hose existing stuff. tempdir = tempfile.mkdtemp(config['paths']['temp_dir_name']) # Putting everything in a `try`...`finally` to ensure `tempdir` is removed # when we're done. We don't want to pollute the user's disk. try: output_path = os.path.expanduser(config['paths']['out']) # Get clan data and war log from API. api = pyroyale.ClashRoyaleAPI(config['api']['api_key'], config['api']['clan_id']) clan = api.clan.clan_info() warlog = api.clan.warlog() current_war = api.clan.current_war() # process data from API current_war_processed = process_current_war(config, current_war) clan_processed = process_clan(config, clan, current_war) member_history = history.get_member_history( clan['memberList'], io.get_previous_history(output_path), current_war) members_processed = process_members(config, clan, warlog, current_war, member_history) recent_wars = process_recent_wars(config, warlog) former_members = process_absent_members(config, member_history['members']) io.parse_templates( config, member_history, tempdir, clan_processed, members_processed, former_members, current_war_processed, recent_wars, get_suggestions(config, members_processed, clan_processed), get_scoring_rules(config)) if (config['crtools']['debug'] == True): # archive outputs of API for debugging io.dump_debug_logs( tempdir, { 'clan': clan, 'warlog': warlog, 'currentwar': current_war, 'clan-processed': clan_processed, 'members-processed': members_processed, 'currentwar-processed': current_war_processed, 'recentwars-processed': recent_wars }) if config['paths']['use_fankit']: fankit.get_fankit(tempdir, output_path) io.copy_static_assets(tempdir, config['paths']['clan_logo'], config['paths']['favicon']) io.move_temp_to_output_dir(tempdir, output_path) except pyroyale.ClashRoyaleAPIAuthenticationError as e: msg = 'developer.clashroyale.com authentication error: {}'.format(e) if not config['api']['api_key']: msg += '\n - API key not provided' else: msg += '\n - API key not valid' logger.error(msg) except pyroyale.ClashRoyaleAPIClanNotFound as e: logger.error('developer.clashroyale.com: {}'.format(e)) except pyroyale.ClashRoyaleAPIError as e: logger.error('developer.clashroyale.com error: {}'.format(e)) except pyroyale.ClashRoyaleAPIMissingFieldsError as e: logger.error('error: {}'.format(e)) finally: # Ensure that temporary directory gets deleted no matter what shutil.rmtree(tempdir)
def build_dashboard(config): # pragma: no coverage """Compile and render clan dashboard.""" logger.debug('crtools version v{}'.format(__version__)) #logger.debug('pyroyale version v{}'.format(pyroyale.__version__)) logger.debug(config) # Create temporary directory. All file writes, until the very end, # will happen in this directory, so that no matter what we do, it # won't hose existing stuff. tempdir = tempfile.mkdtemp(config['paths']['temp_dir_name']) # get API instance configuration = pyroyale.Configuration() configuration.api_key['authorization'] = config['api']['api_key'] api = pyroyale.ClansApi(pyroyale.ApiClient(configuration)) # Putting everything in a `try`...`finally` to ensure `tempdir` is removed # when we're done. We don't want to pollute the user's disk. try: output_path = os.path.expanduser(config['paths']['out']) # Get clan data and war log from API. clan = api.get_clan(config['api']['clan_id']).to_dict() warlog = api.get_clan_war_log(config['api']['clan_id']).to_dict() current_war = api.get_current_war(config['api']['clan_id']).to_dict() # process data from API current_war_processed = process_current_war(config, current_war) clan_processed = process_clan(config, clan, current_war) member_history = history.get_member_history( clan['member_list'], io.get_previous_history(output_path), current_war) members_processed = process_members(config, clan, warlog, current_war, member_history) recent_wars = process_recent_wars(config, warlog) former_members = process_absent_members(config, member_history['members']) io.parse_templates( config, member_history, tempdir, clan_processed, members_processed, former_members, current_war_processed, recent_wars, get_suggestions(config, members_processed, clan_processed), get_scoring_rules(config)) if (config['crtools']['debug'] == True): # archive outputs of API for debugging io.dump_debug_logs( tempdir, { 'clan': clan, 'warlog': warlog, 'currentwar': current_war, 'clan-processed': clan_processed, 'members-processed': members_processed, 'currentwar-processed': current_war_processed, 'recentwars-processed': recent_wars }) # if fankit is previously downloaded, it will copy fankit. Otherwise, # if fankit is enabled, it will download it. fankit.get_fankit(tempdir, output_path, config['paths']['use_fankit']) io.copy_static_assets(tempdir, config['paths']['clan_logo'], config['paths']['favicon']) io.move_temp_to_output_dir(tempdir, output_path) except ApiException as e: logger.error('error: {}'.format(e)) finally: # Ensure that temporary directory gets deleted no matter what shutil.rmtree(tempdir)