diff --git a/docs/operations/data_migration.md b/docs/operations/data_migration.md index 59c2ad52c..4bfe37174 100644 --- a/docs/operations/data_migration.md +++ b/docs/operations/data_migration.md @@ -589,13 +589,22 @@ Example: `cf ssh getgov-za` ## Populate Organization type -This section outlines how to run the `populate_organization_type` script. +This section outlines how to run the `populate_organization_type` script. +The script is used to update the organization_type field on DomainRequest and DomainInformation when it is None. +That data are synthesized from the generic_org_type field and the is_election_board field ### Running on sandboxes #### Step 1: Login to CloudFoundry ```cf login -a api.fr.cloud.gov --sso``` +#### Step 2: Get the domain_election_board file +The latest domain_election_board csv can be found [here](https://drive.google.com/file/d/1aDeCqwHmBnXBl2arvoFCN0INoZmsEGsQ/view). +After downloading this file, place it in `src/migrationdata` + +#### Step 2: Upload the domain_election_board file to your sandbox +Follow [Step 1: Transfer data to sandboxes](#step-1-transfer-data-to-sandboxes) and [Step 2: Transfer uploaded files to the getgov directory](#step-2-transfer-uploaded-files-to-the-getgov-directory) from the [Set Up Migrations on Sandbox](#set-up-migrations-on-sandbox) portion of this doc. + #### Step 2: SSH into your environment ```cf ssh getgov-{space}``` @@ -605,9 +614,9 @@ Example: `cf ssh getgov-za` ```/tmp/lifecycle/shell``` #### Step 4: Running the script -```./manage.py populate_organization_type {domain_election_office_filename} --debug``` +```./manage.py populate_organization_type {domain_election_board_filename} --debug``` -- The domain_election_office_filename file must adhere to this format: +- The domain_election_board_filename file must adhere to this format: - example.gov\ example2.gov\ example3.gov @@ -616,17 +625,25 @@ Example: `./manage.py populate_organization_type migrationdata/election-domains.csv --debug` ### Running locally -```docker-compose exec app ./manage.py populate_organization_type {domain_election_office_filename} --debug``` + +#### Step 1: Get the domain_election_board file +The latest domain_election_board csv can be found [here](https://drive.google.com/file/d/1aDeCqwHmBnXBl2arvoFCN0INoZmsEGsQ/view). +After downloading this file, place it in `src/migrationdata` + + +#### Step 2: Running the script +```docker-compose exec app ./manage.py populate_organization_type {domain_election_board_filename} --debug``` Example (assuming that this is being ran from src/): `docker-compose exec app ./manage.py populate_organization_type migrationdata/election-domains.csv --debug` -##### Required parameters + +### Required parameters | | Parameter | Description | |:-:|:------------------------------------|:-------------------------------------------------------------------| -| 1 | **domain_election_office_filename** | A file containing every domain that is an election office. +| 1 | **domain_election_board_filename** | A file containing every domain that is an election office. -##### Optional parameters +### Optional parameters | | Parameter | Description | |:-:|:-------------------------- |:----------------------------------------------------------------------------| | 1 | **debug** | Increases logging detail. Defaults to False. \ No newline at end of file diff --git a/src/registrar/management/commands/populate_organization_type.py b/src/registrar/management/commands/populate_organization_type.py index a0a1c8633..67fc9397e 100644 --- a/src/registrar/management/commands/populate_organization_type.py +++ b/src/registrar/management/commands/populate_organization_type.py @@ -11,7 +11,11 @@ logger = logging.getLogger(__name__) class Command(BaseCommand): - help = "Loops through each valid DomainInformation and DomainRequest object and updates its organization_type value" + help = ( + "Loops through each valid DomainInformation and DomainRequest object and updates its organization_type value. " + "A valid DomainInformation/DomainRequest in this sense is one that has the value None for organization_type. " + "In other words, we populate the organization_type field if it is not already populated." + ) def __init__(self): super().__init__() @@ -26,34 +30,28 @@ class Command(BaseCommand): self.di_skipped: List[DomainInformation] = [] # Define a global variable for all domains with election offices - self.domains_with_election_offices_set = set() + self.domains_with_election_boards_set = set() def add_arguments(self, parser): """Adds command line arguments""" parser.add_argument("--debug", action=argparse.BooleanOptionalAction) parser.add_argument( - "domain_election_office_filename", + "domain_election_board_filename", help=("A file that contains" " all the domains that are election offices."), ) - def handle(self, domain_election_office_filename, **kwargs): + def handle(self, domain_election_board_filename, **kwargs): """Loops through each valid Domain object and updates its first_created value""" debug = kwargs.get("debug") # Check if the provided file path is valid - if not os.path.isfile(domain_election_office_filename): - raise argparse.ArgumentTypeError(f"Invalid file path '{domain_election_office_filename}'") + if not os.path.isfile(domain_election_board_filename): + raise argparse.ArgumentTypeError(f"Invalid file path '{domain_election_board_filename}'") - with open(domain_election_office_filename, "r") as file: - for line in file: - # Remove any leading/trailing whitespace - domain = line.strip() - if domain not in self.domains_with_election_offices_set: - self.domains_with_election_offices_set.add(domain) + # Read the election office csv + self.read_election_board_file(domain_election_board_filename) - domain_requests = DomainRequest.objects.filter( - organization_type__isnull=True, requested_domain__name__isnull=False - ) + domain_requests = DomainRequest.objects.filter(organization_type__isnull=True) # Code execution will stop here if the user prompts "N" TerminalHelper.prompt_for_execution( @@ -88,12 +86,37 @@ class Command(BaseCommand): self.update_domain_informations(domain_infos, debug) + def read_election_board_file(self, domain_election_board_filename): + """ + Reads the election board file and adds each parsed domain to self.domains_with_election_boards_set. + As previously implied, this file contains information about Domains which have election boards. + + The file must adhere to this format: + ``` + domain1.gov + domain2.gov + domain3.gov + ``` + (and so on) + """ + with open(domain_election_board_filename, "r") as file: + for line in file: + # Remove any leading/trailing whitespace + domain = line.strip() + if domain not in self.domains_with_election_boards_set: + self.domains_with_election_boards_set.add(domain) + def update_domain_requests(self, domain_requests, debug): + """ + Updates the organization_type for a list of DomainRequest objects using the `sync_organization_type` function. + Results are then logged. + Debug mode provides detailed logging. + """ for request in domain_requests: try: if request.generic_org_type is not None: domain_name = request.requested_domain.name - request.is_election_board = domain_name in self.domains_with_election_offices_set + request.is_election_board = domain_name in self.domains_with_election_boards_set request = self.sync_organization_type(DomainRequest, request) self.request_to_update.append(request) @@ -120,11 +143,16 @@ class Command(BaseCommand): ) def update_domain_informations(self, domain_informations, debug): + """ + Updates the organization_type for a list of DomainInformation objects using the `sync_organization_type` function. + Results are then logged. + Debug mode provides detailed logging. + """ for info in domain_informations: try: if info.generic_org_type is not None: domain_name = info.domain.name - info.is_election_board = domain_name in self.domains_with_election_offices_set + info.is_election_board = domain_name in self.domains_with_election_boards_set info = self.sync_organization_type(DomainInformation, info) self.di_to_update.append(info) if debug: @@ -168,7 +196,7 @@ class Command(BaseCommand): election_org_map = DomainRequest.OrgChoicesElectionOffice.get_org_election_to_org_generic() # Manages the "organization_type" variable and keeps in sync with - # "is_election_office" and "generic_organization_type" + # "is_election_board" and "generic_organization_type" org_type_helper = CreateOrUpdateOrganizationTypeHelper( sender=sender, instance=instance,