import random import string from django.db.models.signals import pre_save, post_save, pre_delete from django.dispatch import receiver from django.conf import settings from .models import Club, Tournament, FailedApiCall, Log, TeamRegistration from tournaments.services.email_service import TournamentEmailService from tournaments.services.email_service import TeamEmailType from shared.discord import send_discord_log_message, send_discord_failed_calls_message from .utils.extensions import is_not_sqlite_backend def generate_unique_code(): characters = string.ascii_lowercase + string.digits while True: code = ''.join(random.sample(characters, 3)) if not Club.objects.filter(broadcast_code=code).exists(): return code @receiver(post_save, sender=Club) def assign_unique_code(sender, instance, **kwargs): if not instance.broadcast_code: instance.broadcast_code = generate_unique_code() instance.save() @receiver(post_save, sender=FailedApiCall) def notify_discord_on_create(sender, instance, created, **kwargs): notify_object_creation_on_discord(created, instance) @receiver(post_save, sender=Log) def notify_log_creation_on_discord(sender, instance, created, **kwargs): notify_object_creation_on_discord(created, instance) # WARNING: using this method requires the instance to have a discord_string method def notify_object_creation_on_discord(created, instance): if created: default_db_engine = settings.DATABASES['default']['ENGINE'] if default_db_engine != 'django.db.backends.sqlite3': site_name = settings.SITE_NAME if hasattr(instance, 'discord_string'): message = f'{site_name} > {instance.__class__.__name__} created: {instance.discord_string()}' else: message = "no message. Please configure 'discord_string' on your instance" if isinstance(instance, FailedApiCall): send_discord_failed_calls_message(message) else: send_discord_log_message(message) def notify_team(team, tournament, message_type): print(team, message_type) # if tournament.enable_online_registration is False: # print("returning because tournament.enable_online_registration false") # return if team.has_registered_online() is False: print("returning because team.has_registered_online false") return if tournament.has_ended(): print("returning because tournament.has_ended") return if tournament.has_started(): print("returning because tournament.has_started") return if is_not_sqlite_backend(): print("is_not_sqlite_backend") TournamentEmailService.notify_team(team, tournament, message_type) @receiver(pre_delete, sender=TeamRegistration) def unregister_team(sender, instance, **kwargs): if not instance.tournament: return if instance.tournament.is_deleted: return if instance.tournament.enable_online_registration is False: return notify_team(instance, instance.tournament, TeamEmailType.UNREGISTERED) teams = instance.tournament.teams(True) # Check if the team being deleted is in the waiting list team_being_deleted = next((team for team in teams if team.team_registration.id == instance.id), None) is_team_in_waiting_list = team_being_deleted and team_being_deleted.team_registration.out_of_tournament() == True # Only notify the first waiting list team if the deleted team is NOT in the waiting list if not is_team_in_waiting_list: first_waiting_list_team = instance.tournament.first_waiting_list_team(teams) if first_waiting_list_team and first_waiting_list_team.id != instance.id: if instance.tournament.automatic_waiting_list(): waiting_list_teams = instance.tournament.waiting_list_teams(teams) ttc = None if waiting_list_teams is not None: ttc = instance.tournament.calculate_time_to_confirm(len(waiting_list_teams)) first_waiting_list_team.set_time_to_confirm(ttc) notify_team(first_waiting_list_team, instance.tournament, TeamEmailType.OUT_OF_WAITING_LIST) @receiver(post_save, sender=Tournament) def notify_players_of_tournament_cancellation(sender, instance, **kwargs): if not instance.is_deleted: return if instance.enable_online_registration is False: return for team_registration in instance.team_registrations.all(): notify_team(team_registration, instance, TeamEmailType.TOURNAMENT_CANCELED) @receiver(pre_save, sender=Tournament) def check_waiting_list(sender, instance, **kwargs): if instance.id is None: return if instance.enable_online_registration is False: return try: previous_state = Tournament.objects.get(id=instance.id) except Tournament.DoesNotExist: previous_state = None if previous_state is None: return teams_out_to_warn = [] teams_in_to_warn = [] previous_state_teams = previous_state.teams(True) if previous_state.team_count > instance.team_count: teams_that_will_be_out = instance.teams(True)[instance.team_count:] teams_out_to_warn = [ team for team in teams_that_will_be_out if team.stage != "Attente" ] elif previous_state.team_count < instance.team_count: teams_that_will_be_in = previous_state_teams[previous_state.team_count:instance.team_count] teams_in_to_warn = [ team for team in teams_that_will_be_in if team.stage == "Attente" ] waiting_list_teams = previous_state.waiting_list_teams(previous_state_teams) automatic_waiting_list = instance.automatic_waiting_list() ttc = None for team in teams_in_to_warn: if automatic_waiting_list: if waiting_list_teams is not None: ttc = previous_state.calculate_time_to_confirm(len(waiting_list_teams)) team.team_registration.set_time_to_confirm(ttc) notify_team(team.team_registration, instance, TeamEmailType.IN_TOURNAMENT_STRUCTURE) for team in teams_out_to_warn: team.team_registration.cancel_time_to_confirm() notify_team(team.team_registration, instance, TeamEmailType.OUT_OF_TOURNAMENT_STRUCTURE) @receiver(pre_save, sender=TeamRegistration) def warn_team_walkout_status_change(sender, instance, **kwargs): if instance.id is None or instance.tournament is None or instance.tournament.enable_online_registration is False: return print("warn_team_walkout_status_change", instance) previous_instance = None try: previous_instance = TeamRegistration.objects.get(id=instance.id) except TeamRegistration.DoesNotExist: print("warn_team_walkout > TeamRegistration.DoesNotExist") return ttc = None previous_teams = instance.tournament.teams(True) current_teams = instance.tournament.teams(True, instance) previous_retrieved_teams = [team for team in previous_teams if team.team_registration.id == previous_instance.id] current_retrieved_teams = [team for team in current_teams if team.team_registration.id == instance.id] was_out = previous_instance.out_of_tournament() is_out = instance.out_of_tournament() if len(previous_retrieved_teams) > 0 and previous_retrieved_teams[0].stage == "Attente": was_out = True if len(current_retrieved_teams) > 0 and current_retrieved_teams[0].stage == "Attente": is_out = True print(was_out, previous_instance.out_of_tournament(), is_out, instance.out_of_tournament()) if not instance.out_of_tournament() and is_out and (previous_instance.out_of_tournament() or not was_out): instance.cancel_time_to_confirm() notify_team(instance, instance.tournament, TeamEmailType.OUT_OF_WALKOUT_WAITING_LIST) elif was_out and not is_out: if instance.tournament.automatic_waiting_list(): waiting_list_teams = instance.tournament.waiting_list_teams(current_teams) if waiting_list_teams is not None: ttc = instance.tournament.calculate_time_to_confirm(len(waiting_list_teams)) instance.set_time_to_confirm(ttc) notify_team(instance, instance.tournament, TeamEmailType.OUT_OF_WALKOUT_IS_IN) elif not previous_instance.out_of_tournament() and instance.out_of_tournament(): instance.cancel_time_to_confirm() print("User did cancel registration", instance.user_did_cancel_registration()) if instance.user_did_cancel_registration(): notify_team(instance, instance.tournament, TeamEmailType.UNREGISTERED) else: notify_team(instance, instance.tournament, TeamEmailType.WALKOUT) if was_out and not is_out: first_out_of_list = instance.tournament.first_waiting_list_team(current_teams) if first_out_of_list: first_out_of_list.cancel_time_to_confirm() notify_team(first_out_of_list, instance.tournament, TeamEmailType.UNEXPECTED_OUT_OF_TOURNAMENT) elif not was_out and is_out: first_waiting_list_team = instance.tournament.first_waiting_list_team(previous_teams) if first_waiting_list_team: if instance.tournament.automatic_waiting_list(): waiting_list_teams = instance.tournament.waiting_list_teams(current_teams) if waiting_list_teams is not None: ttc = instance.tournament.calculate_time_to_confirm(len(waiting_list_teams)) first_waiting_list_team.set_time_to_confirm(ttc) notify_team(first_waiting_list_team, instance.tournament, TeamEmailType.OUT_OF_WAITING_LIST) @receiver(post_save, sender=TeamRegistration) def team_confirm_if_placed(sender, instance, **kwargs): if instance.id is None or instance.tournament is None: return instance.confirm_if_placed()