Skip to content
Open
Changes from 2 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
67 changes: 63 additions & 4 deletions openedx/core/djangoapps/user_api/accounts/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
"""

import datetime
import json
import logging
import re
from functools import wraps

import pytz
Expand Down Expand Up @@ -1118,26 +1120,83 @@ def post(self, request):
user_id = retirement.user.id
except AttributeError:
user_id = 'unknown'

error_details = {
'error_type': 'RetirementStateError',
'user_id': user_id,
'original_error': str(exc),
'timestamp': datetime.datetime.now(pytz.UTC).isoformat()
}

try:
current_responses = json.loads(retirement.responses) if retirement.responses else []
current_responses.append(error_details)
retirement.responses = json.dumps(current_responses)
retirement.save()
except (json.JSONDecodeError, AttributeError):
pass

log_error = self._sanitize_error_message(str(exc))
log.error(
'RetirementStateError during user retirement: user_id=%s, error=%s',
user_id, str(exc)
user_id, log_error
)
record_exception()
return Response(str(exc), status=status.HTTP_400_BAD_REQUEST)
return Response("RetirementStateError occurred during retirement", status=status.HTTP_400_BAD_REQUEST)
except Exception as exc: # pylint: disable=broad-except
try:
user_id = retirement.user.id
except AttributeError:
user_id = 'unknown'

error_details = {
'error_type': type(exc).__name__,
'user_id': user_id,
'original_error': str(exc),
'timestamp': datetime.datetime.now(pytz.UTC).isoformat()
}

try:
current_responses = json.loads(retirement.responses) if retirement.responses else []
current_responses.append(error_details)
retirement.responses = json.dumps(current_responses)
retirement.save()
except (json.JSONDecodeError, AttributeError):
pass

log_error = self._sanitize_error_message(str(exc))
log.error(
'Unexpected error during user retirement: user_id=%s, error=%s',
user_id, str(exc)
user_id, log_error
)
record_exception()
return Response(str(exc), status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return Response("Internal error occurred during retirement", status=status.HTTP_500_INTERNAL_SERVER_ERROR)

return Response(status=status.HTTP_204_NO_CONTENT)

def _sanitize_error_message(self, error_message):
"""
Remove common PII from error messages while preserving debugging context.

Args:
error_message (str): The original error message

Returns:
str: Error message with PII removed
"""
if not error_message:
return error_message

message = error_message

message = re.sub(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b',
'-', message, flags=re.IGNORECASE)

message = re.sub(r"username='[^']*'", "username='-'", message)
message = re.sub(r'username="[^"]*"', 'username="-"', message)

return message


class AccountRetirementView(ViewSet):
"""
Expand Down
Loading