Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import copy
import logging

from django.core.management.base import BaseCommand
from django.db import transaction
from integrations.models import Integration, RouteConfiguration


DEFAULT_FIELD_MAPPING = {"default": "", "destination_field": "provider_key"}


class Command(BaseCommand):

help = "Gundi v2 field mapping creation script"
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The help text for this command is generic and doesn't clearly explain what the script does or when it should be used. Consider adding a more descriptive help text that explains the purpose of creating field mappings between integrations and what the expected outcome is. For example: "Creates or updates field mapping configuration between a source integration and destination integration using a provider key."

Suggested change
help = "Gundi v2 field mapping creation script"
help = (
"Creates or updates field mapping configuration between a source integration and a "
"destination integration using a provider key. "
"This command should be used to establish or modify how fields are mapped from the source "
"integration to the destination integration in Gundi v2. "
"Expected outcome: the specified field mapping is created or updated for the given integrations."
)

Copilot uses AI. Check for mistakes.

def add_arguments(self, parser):
parser.add_argument(
"--connection-id",
type=str,
required=True,
help="Specify the Gundi v2 connection ID [REQUIRED]",
)
parser.add_argument(
"--destination-id",
type=str,
required=True,
help="Specify the Gundi v2 destination ID [REQUIRED]",
)
parser.add_argument(
'--provider-key',
type=str,
required=True,
help='Provider key to be used in field mapping creation [REQUIRED]'
Comment on lines +30 to +33
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Inconsistent quote style: The first two arguments use double quotes for the argument name (lines 18, 24), but the third argument uses single quotes (line 30). For consistency, use double quotes for all argument names, or follow the project's style guide if it specifies a preference.

Suggested change
'--provider-key',
type=str,
required=True,
help='Provider key to be used in field mapping creation [REQUIRED]'
"--provider-key",
type=str,
required=True,
help="Provider key to be used in field mapping creation [REQUIRED]"

Copilot uses AI. Check for mistakes.
)

def handle(self, *args, **options):

# TODO: FOR LOCAL EXECUTION ONLY! Remove if running in pod
logging.getLogger('django.db.backends').setLevel(logging.WARNING)
logging.getLogger('activity_log.mixins').setLevel(logging.ERROR)
logging.getLogger('integrations.tasks').setLevel(logging.WARNING)

connection_id = options["connection_id"]
destination_id = options["destination_id"]
provider_key = options["provider_key"]

try:
with transaction.atomic():
try:
source_integration = Integration.objects.get(
id=connection_id,
)
except Integration.DoesNotExist:
self.stdout.write(f" -- ERROR: Connection ID {connection_id} does not exist in Gundi v2 -- ")
return

try:
destination_integration = Integration.objects.get(
id=destination_id,
)
except Integration.DoesNotExist:
self.stdout.write(f" -- ERROR: Destination ID {destination_id} does not exist in Gundi v2 -- ")
Comment on lines +54 to +62
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error messages on lines 54 and 62 are written to self.stdout instead of self.stderr. Error messages should be written to stderr for proper error handling and to allow users to separate normal output from error output. Change these to self.stderr.write().

Copilot uses AI. Check for mistakes.
return
Comment on lines +48 to +63
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The transaction will be rolled back on error (due to the transaction.atomic() context), but the script returns early without rolling back when integrations are not found (lines 54-55, 62-63). This creates inconsistent behavior where some errors cause rollback and others don't. Additionally, returning inside a transaction block that will be exited normally means the transaction commits successfully even though an error was reported. Consider raising an exception or using a different error handling strategy to ensure consistent transaction handling.

Copilot uses AI. Check for mistakes.

self.stdout.write(f" -- Connection: {source_integration.name} -- \n")
self.stdout.write(f" -- Destination: {destination_integration.name} -- \n")
self.stdout.write(f" -- Provider Key: {provider_key} -- \n\n")

field_mappings = {
str(source_integration.id): {
"obv": {}
Comment on lines +69 to +71
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The nested structure uses a hardcoded key "obv" without explanation of what it represents or why this specific key is used. Add a comment explaining the meaning and purpose of this key in the field mapping structure, or consider using a named constant to make the code more self-documenting.

Copilot uses AI. Check for mistakes.
}
}

inbound_field_mapping = copy.deepcopy(DEFAULT_FIELD_MAPPING)
inbound_field_mapping["default"] = provider_key

field_mappings[str(source_integration.id)]["obv"][str(destination_integration.id)] = inbound_field_mapping

field_mappings_result = {
"field_mappings": field_mappings
}
route_config, created = RouteConfiguration.objects.get_or_create(
name=f"{source_integration.default_route.name} (Integration ID: {source_integration.id}) - Default Config",
defaults={
"data": field_mappings_result
}
)
Comment on lines +83 to +88
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using get_or_create with only the name field as the unique identifier can be problematic if multiple integrations could have the same route name pattern. This could lead to unintended sharing of RouteConfiguration objects between different integrations. Consider adding a unique constraint or using the integration ID in a more unique way (e.g., as part of a unique_together constraint with name, or using update_or_create with a more specific lookup).

Copilot uses AI. Check for mistakes.

if not created:
# A route config already exists for this integration/connection, we need to update it
route_config.data = field_mappings_result
route_config.save()

source_integration.default_route.configuration = route_config
source_integration.default_route.save()

self.stdout.write(f" -- Connection '{source_integration.name}' (ID: '{source_integration.id}') route config (field_mapping) created correctly... -- \n")
self.stdout.write(f" -- Name: '{route_config.name}', ID: '{route_config.id}' ... -- \n\n")

except Exception as e:
self.stderr.write(f" -- ERROR creating field mapping for connection ID {connection_id}, destination ID: {destination_id}: {e}")
raise
Loading