Skip to content

Commit

Permalink
feat: Added management command to update UIDs
Browse files Browse the repository at this point in the history
  • Loading branch information
zamanafzal committed Dec 9, 2024
1 parent 7ca0731 commit b4462f2
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ Unreleased
----------
* nothing unreleased

[5.4.1]
--------
* feat: Added a management command to update the Social Auth UID's for an enterprise.

[5.4.0]
--------
* chore: Update python requirements.
Expand Down
2 changes: 1 addition & 1 deletion enterprise/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
Your project description goes here.
"""

__version__ = "5.4.0"
__version__ = "5.4.1"
164 changes: 164 additions & 0 deletions enterprise/management/commands/update_enterprise_social_auth_uids.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
"""
Django management command to update the social auth records UID
"""

import logging
import csv
from django.db import transaction
from django.core.management.base import BaseCommand
from django.core.exceptions import ValidationError

Check warning on line 9 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L5-L9

Added lines #L5 - L9 were not covered by tests

try:
from social_django.models import UserSocialAuth
except ImportError:
UserSocialAuth = None

Check warning on line 14 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L11-L14

Added lines #L11 - L14 were not covered by tests

logger = logging.getLogger(__name__)

Check warning on line 16 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L16

Added line #L16 was not covered by tests


class CSVUpdateError(Exception):

Check warning on line 19 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L19

Added line #L19 was not covered by tests
"""Custom exception for CSV update process."""
pass # pylint: disable=unnecessary-pass

Check warning on line 21 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L21

Added line #L21 was not covered by tests


class Command(BaseCommand):

Check warning on line 24 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L24

Added line #L24 was not covered by tests
"""
Update the enterprise related social auth records UID to the new one.
Example usage:
./manage.py lms update_enterprise_social_auth_uids csv_file_path
./manage.py lms update_enterprise_social_auth_uids csv_file_path --old-prefix="slug:" --new-prefix="slug:x|{}@xyz"
./manage.py lms update_enterprise_social_auth_uids csv_file_path --no-dry-run
"""

help = 'Records update from CSV with console logging'

Check warning on line 35 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L35

Added line #L35 was not covered by tests

def add_arguments(self, parser):
parser.add_argument('csv_file', type=str, help='Path to the CSV file')
parser.add_argument(

Check warning on line 39 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L37-L39

Added lines #L37 - L39 were not covered by tests
'--old_prefix',
type=str,
default=None,
help='Optional old prefix for old UID. If not provided, uses CSV value.'
)
parser.add_argument(

Check warning on line 45 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L45

Added line #L45 was not covered by tests
'--new_prefix',
type=str,
default=None,
help='Optional new prefix for new UID. If not provided, uses CSV value.'
)
parser.add_argument(

Check warning on line 51 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L51

Added line #L51 was not covered by tests
'--no-dry-run',
action='store_false',
dest='dry_run',
default=True,
help='Actually save changes instead of simulating'
)

def handle(self, *args, **options):
logger.info("Command has started...")
csv_path = options['csv_file']
dry_run = options['dry_run']
old_prefix = options['old_prefix']
new_prefix = options['new_prefix']

Check warning on line 64 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L59-L64

Added lines #L59 - L64 were not covered by tests

total_processed = 0
total_updated = 0
total_errors = 0

Check warning on line 68 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L66-L68

Added lines #L66 - L68 were not covered by tests

try:
with open(csv_path, 'r') as csvfile:
reader = csv.DictReader(csvfile)

Check warning on line 72 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L70-L72

Added lines #L70 - L72 were not covered by tests

for row_num, row in enumerate(reader, start=1):
total_processed += 1

Check warning on line 75 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L75

Added line #L75 was not covered by tests

try:
with transaction.atomic():

Check warning on line 78 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L77-L78

Added lines #L77 - L78 were not covered by tests
if self.update_record(row, dry_run, old_prefix, new_prefix):
total_updated += 1

Check warning on line 80 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L80

Added line #L80 was not covered by tests

except Exception as row_error: # pylint: disable=broad-except
total_errors += 1
error_msg = f"Row {row_num} update failed: {row} - Error: {str(row_error)}"
logger.error(error_msg, exc_info=True)

Check warning on line 85 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L82-L85

Added lines #L82 - L85 were not covered by tests

summary_msg = (

Check warning on line 87 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L87

Added line #L87 was not covered by tests
f"CSV Update Summary:\n"
f"Total Records Processed: {total_processed}\n"
f"Records Successfully Updated: {total_updated}\n"
f"Errors Encountered: {total_errors}\n"
f"Dry Run Mode: {'Enabled' if dry_run else 'Disabled'}"
)
logger.info(summary_msg)
except IOError as io_error:
logger.critical(f"File I/O error: {str(io_error)}")

Check warning on line 96 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L94-L96

Added lines #L94 - L96 were not covered by tests

except Exception as e: # pylint: disable=broad-except
logger.critical(f"Critical error in CSV processing: {str(e)}")

Check warning on line 99 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L98-L99

Added lines #L98 - L99 were not covered by tests

def update_record(self, row, dry_run=True, old_prefix=None, new_prefix=None):

Check warning on line 101 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L101

Added line #L101 was not covered by tests
"""
Update a single record, applying optional prefixes to UIDs if provided.
Args:
row (dict): CSV row data
dry_run (bool): Whether to simulate or actually save changes
old_prefix (str): Prefix to apply to the old UID
new_prefix (str): Prefix to apply to the new UID
Returns:
bool: Whether the update was successful
"""
try:
old_uid = row.get('old-uid')
new_uid = row.get('new-uid')

Check warning on line 116 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L114-L116

Added lines #L114 - L116 were not covered by tests

# Validating that both values are present
if not old_uid or not new_uid:
raise CSVUpdateError("Missing required UID fields")

Check warning on line 120 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L120

Added line #L120 was not covered by tests

# Construct dynamic UIDs
old_uid_with_prefix = f'{old_prefix}{old_uid}' if old_prefix else old_uid
new_uid_with_prefix = (

Check warning on line 124 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L123-L124

Added lines #L123 - L124 were not covered by tests
new_prefix.format(new_uid) if new_prefix and '{}' in new_prefix
else f"{new_prefix}{new_uid}" if new_prefix
else new_uid
)

instance_with_old_uid = UserSocialAuth.objects.filter(uid=old_uid_with_prefix).first()

Check warning on line 130 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L130

Added line #L130 was not covered by tests

if not instance_with_old_uid:
raise CSVUpdateError(f"No record found with old UID {old_uid_with_prefix}")

Check warning on line 133 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L133

Added line #L133 was not covered by tests

instance_with_new_uid = UserSocialAuth.objects.filter(uid=new_uid_with_prefix).first()

Check warning on line 135 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L135

Added line #L135 was not covered by tests
if instance_with_new_uid:
log_entry = f"Warning: Existing record with new UID {new_uid_with_prefix} is deleting."
logger.info(log_entry)

Check warning on line 138 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L137-L138

Added lines #L137 - L138 were not covered by tests
if not dry_run:
instance_with_new_uid.delete()

Check warning on line 140 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L140

Added line #L140 was not covered by tests

if not dry_run:
instance_with_old_uid.uid = new_uid_with_prefix
instance_with_old_uid.save()

Check warning on line 144 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L143-L144

Added lines #L143 - L144 were not covered by tests

log_entry = f"Successfully updated record: Old UID {old_uid_with_prefix} → New UID {new_uid_with_prefix}"
logger.info(log_entry)

Check warning on line 147 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L146-L147

Added lines #L146 - L147 were not covered by tests

return True

Check warning on line 149 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L149

Added line #L149 was not covered by tests

except ValidationError as ve:
error_msg = f"Validation error: {ve}"
logger.error(error_msg)
raise

Check warning on line 154 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L151-L154

Added lines #L151 - L154 were not covered by tests

except CSVUpdateError as update_error:
error_msg = f"Update processing error: {update_error}"
logger.error(error_msg)
raise

Check warning on line 159 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L156-L159

Added lines #L156 - L159 were not covered by tests

except Exception as e:
error_msg = f"Unexpected error during record update: {e}"
logger.error(error_msg, exc_info=True)
raise

Check warning on line 164 in enterprise/management/commands/update_enterprise_social_auth_uids.py

View check run for this annotation

Codecov / codecov/patch

enterprise/management/commands/update_enterprise_social_auth_uids.py#L161-L164

Added lines #L161 - L164 were not covered by tests

0 comments on commit b4462f2

Please sign in to comment.