diff --git a/core/management/commands/add_clubs.py b/core/management/commands/add_clubs.py index b0d34dc6..a5a04eee 100644 --- a/core/management/commands/add_clubs.py +++ b/core/management/commands/add_clubs.py @@ -10,6 +10,7 @@ import csv from io import StringIO +import re import requests from django.core.management.base import BaseCommand @@ -31,6 +32,11 @@ def success(self, *args, **kwargs): self.style.SUCCESS(*args, **kwargs), ) + def warn(self, *args, **kwargs): + self.stdout.write( + self.style.WARNING(*args, **kwargs), + ) + def add_arguments(self, parser): parser.add_argument( "sheets_link", @@ -71,17 +77,19 @@ def handle(self, *args, **options): expected_header == next(csv_reader) ), "Google Sheets layout changed since the last time the script was updated, please consult the backend team." + skipped_orgs = [] for row in csv_reader: organization_is_not_approved = row[1] != "TRUE" has_duplicate_owner = len(row[0]) == 0 - if organization_is_not_approved: - self.error(f"Skipping {row[0]} because it is not approved\n") + if has_duplicate_owner: + # self.error(f"Skipping a row because it is a duplicate owner of the previously added club\n") # logging this is probably not necessary continue - elif has_duplicate_owner: - self.error(f"Skipping {row[0]} as it's a duplicate owner\n") + elif organization_is_not_approved: + self.error(f"Skipping {row[0]} because it is not approved\n") continue - self.success(f"New organization: {row[0]}") + self.success(f"\nNew organization: {row[0]}") + row = [token.strip() for token in row] ( organization_name, _, @@ -97,6 +105,7 @@ def handle(self, *args, **options): club_owner = self.get_user_by_email(owner_name, owner_email) if club_owner == "skipped": # prevent a repeat of the same error message + skipped_orgs.append(organization_name) continue supervisor_user = self.get_user_by_email(staff_name, staff_email) @@ -112,6 +121,7 @@ def handle(self, *args, **options): self.error( f"Skipping {organization_name} as {user_statuses} is not found\n" ) + skipped_orgs.append(organization_name) continue try: @@ -125,15 +135,20 @@ def handle(self, *args, **options): "is_active": True, "is_open": True, "applications_open": True, - }, + } # this singular comma gave me a run for my money. i have lost my family, my wealth, my sanity, and my soul from the inclusion of this character. # fmt: on + # remove all non-alphanumeric or whitespace characters (a-z, A-Z, 0-9, space) and then replace spaces with dashes + slug = re.sub( + r"[^a-zA-Z0-9\s]", "", organization_name.strip().casefold() + ).replace(" ", "-") + + if not Organization.objects.filter(slug=slug).exists(): + slug = self.get_corrected_slug_or_not(organization_name, slug) + if not options["dry_run"]: club, created = Organization.objects.update_or_create( - slug="".join( - c.casefold() if c.isalnum() else "-" - for c in organization_name - ).lower(), + slug=slug, defaults=defaults, create_defaults={ **defaults, @@ -147,17 +162,22 @@ def handle(self, *args, **options): else: status = "(dry-run | would have added)" self.success( - f"\tSuccessfully {status} {organization_name} organization, owned by {owner_name}" + f"\tSuccessfully {status} '{organization_name}' organization (slug={slug}), owned by {owner_name}" ) except IntegrityError as IE: self.error(IE.__traceback__) self.stdout.write() + self.warn( + f"Skipped {len(skipped_orgs)} organizations: \n\t{'\n\t'.join(skipped_orgs)}" + ) + self.success("Done!") + type Status = "skipped" # noqa: F821 def get_user_by_email(self, name: str, email: str) -> User | Status: try: - return User.objects.get(email=email) + return User.objects.get(email__iexact=email) except User.DoesNotExist: self.error( f"\t{name}'s email ({email}) not found! Are you sure they registered a metro account with this email?" @@ -179,3 +199,21 @@ def get_user_by_email(self, name: str, email: str) -> User | Status: ) self.stdout.write("\tPlease re-enter email:") + + def get_corrected_slug_or_not(self, organization_name: str, slug: str) -> str: + self.warn( + f"\tCould not find '{organization_name}' with the slug '{slug}'. Please enter the correct slug if the organization exists or leave blank to create club" + ) + + while True: + print("\t", end="") + new_slug = input() + + if new_slug == "": + return slug + elif Organization.objects.filter(slug=new_slug).exists(): + return new_slug + else: + self.error( + f"\tCould not find an organization with the slug '{new_slug}'. Please try again or leave blank to create a club." + )