Skip to content
13 changes: 10 additions & 3 deletions cms/djangoapps/course_creators/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,11 @@ def send_user_notification_callback(sender, **kwargs): # pylint: disable=unused

try:
user.email_user(subject, message, studio_request_email)
except: # pylint: disable=bare-except
log.warning("Unable to send course creator status e-mail to %s", user.email)
except: # lint-amnesty, pylint: disable=bare-except
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.warning("Unable to send course creator status e-mail to user ID %s", user.id)
else:
log.warning("Unable to send course creator status e-mail to %s", user.email)


@receiver(send_admin_notification, sender=CourseCreator)
Expand All @@ -179,6 +182,7 @@ def send_admin_notification_callback(sender, **kwargs): # pylint: disable=unuse
"""
user = kwargs['user']

# studio_request_email is a system email address, not PII, which can safely be logged.
context = course_creator_notification_context(user)
studio_request_email = context['studio_request_email']

Expand All @@ -195,7 +199,10 @@ def send_admin_notification_callback(sender, **kwargs): # pylint: disable=unuse
fail_silently=False
)
except SMTPException:
log.warning("Failure sending 'pending state' e-mail for %s to %s", user.email, studio_request_email)
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.warning("Failure sending 'pending state' e-mail for user ID %s to %s", user.id, studio_request_email)
else:
log.warning("Failure sending 'pending state' e-mail for %s to %s", user.email, studio_request_email)


@receiver(m2m_changed, sender=CourseCreator.organizations.through)
Expand Down
10 changes: 8 additions & 2 deletions common/djangoapps/student/emails.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,14 @@ def send_proctoring_requirements_email(context):
user_context={'full_name': user.profile.name}
)
ace.send(msg)
log.info('Proctoring requirements email sent to user: %r', user.username)
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.info('Proctoring requirements email sent to user ID: %r', user.id)
else:
log.info('Proctoring requirements email sent to user: %r', user.username)
return True
except Exception: # pylint: disable=broad-except
log.exception('Could not send email for proctoring requirements to user %s', user.username)
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.exception('Could not send email for proctoring requirements to user ID %s', user.id)
else:
log.exception('Could not send email for proctoring requirements to user %s', user.username)
return False
89 changes: 63 additions & 26 deletions common/djangoapps/student/models/course_enrollment.py
Original file line number Diff line number Diff line change
Expand Up @@ -664,12 +664,20 @@ def emit_event(self, event_name, enterprise_uuid=None):

except Exception: # pylint: disable=broad-except
if event_name and self.course_id:
log.exception(
'Unable to emit event %s for user %s and course %s',
event_name,
self.user.username,
self.course_id,
)
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.exception(
'Unable to emit event %s for user %s and course %s',
event_name,
self.user.id,
self.course_id,
)
else:
log.exception(
'Unable to emit event %s for user %s and course %s',
event_name,
self.user.username,
self.course_id,
)

@classmethod
def enroll(cls, user, course_key, mode=None, check_access=False, can_upgrade=False, enterprise_uuid=None):
Expand Down Expand Up @@ -731,40 +739,66 @@ def enroll(cls, user, course_key, mode=None, check_access=False, can_upgrade=Fal
course_key=course.id,
display_name=course.display_name,
)
except CourseOverview.DoesNotExist:
except CourseOverview.DoesNotExist as err:
# This is here to preserve legacy behavior which allowed enrollment in courses
# announced before the start of content creation.
course_data = CourseData(
course_key=course_key,
)
if check_access:
log.warning("User %s failed to enroll in non-existent course %s", user.username, str(course_key))
raise NonExistentCourseError # pylint: disable=raise-missing-from # noqa: B904
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.warning("User %s failed to enroll in non-existent course %s", user.id, str(course_key))
else:
log.warning("User %s failed to enroll in non-existent course %s", user.username, str(course_key))
raise NonExistentCourseError from err # lint-amnesty, pylint: disable=raise-missing-from

if check_access:
if cls.is_enrollment_closed(user, course) and not can_upgrade:
log.warning(
"User %s failed to enroll in course %s because enrollment is closed (can_upgrade=%s).",
user.username,
str(course_key),
can_upgrade,
)
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.warning(
"User %s failed to enroll in course %s because enrollment is closed (can_upgrade=%s).",
user.id,
str(course_key),
can_upgrade,
)
else:
log.warning(
"User %s failed to enroll in course %s because enrollment is closed (can_upgrade=%s).",
user.username,
str(course_key),
can_upgrade,
)
raise EnrollmentClosedError

if cls.objects.is_course_full(course):
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.warning(
"Course %s has reached its maximum enrollment of %d learners. User %s failed to enroll.",
str(course_key),
course.max_student_enrollments_allowed,
user.id,
)
else:
log.warning(
"Course %s has reached its maximum enrollment of %d learners. User %s failed to enroll.",
str(course_key),
course.max_student_enrollments_allowed,
user.username,
)
raise CourseFullError
if cls.is_enrolled(user, course_key):
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.warning(
"User %s attempted to enroll in %s, but they were already enrolled",
user.id,
str(course_key)
)
else:
log.warning(
"Course %s has reached its maximum enrollment of %d learners. User %s failed to enroll.",
str(course_key),
course.max_student_enrollments_allowed,
"User %s attempted to enroll in %s, but they were already enrolled",
user.username,
str(course_key)
)
raise CourseFullError
if cls.is_enrolled(user, course_key):
log.warning(
"User %s attempted to enroll in %s, but they were already enrolled",
user.username,
str(course_key)
)
if check_access:
raise AlreadyEnrolledError

Expand Down Expand Up @@ -829,7 +863,10 @@ def enroll_by_email(cls, email, course_id, mode=None, ignore_errors=True):
return cls.enroll(user, course_id, mode)
except User.DoesNotExist:
err_msg = "Tried to enroll email {} into course {}, but user not found"
log.error(err_msg.format(email, course_id))
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.error("Tried to enroll a redacted email into course %s, but user not found", course_id)
else:
log.error(err_msg.format(email, course_id))
if ignore_errors:
return None
raise
Expand Down
5 changes: 4 additions & 1 deletion common/djangoapps/student/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,10 @@ def activate(self): # pylint: disable=missing-function-docstring
self.activation_timestamp = datetime.utcnow()
self.save()
USER_ACCOUNT_ACTIVATED.send_robust(self.__class__, user=self.user)
log.info('User %s (%s) account is successfully activated.', self.user.username, self.user.email)
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.info('User %s account is successfully activated.', self.user.id)
else:
log.info('User %s (%s) account is successfully activated.', self.user.username, self.user.email)


class PendingNameChange(DeletableByUserValue, models.Model): # noqa: DJ008
Expand Down
45 changes: 35 additions & 10 deletions common/djangoapps/student/views/management.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,10 @@ def change_enrollment(request, check_access=True):
except UnenrollmentNotAllowed as exc:
return HttpResponseBadRequest(str(exc))

log.info("User %s unenrolled from %s; sending REFUND_ORDER", user.username, course_id)
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.info("User %s unenrolled from %s; sending REFUND_ORDER", user.id, course_id)
else:
log.info("User %s unenrolled from %s; sending REFUND_ORDER", user.username, course_id)
REFUND_ORDER.send(sender=None, course_enrollment=enrollment)
return HttpResponse()
else:
Expand Down Expand Up @@ -557,11 +560,17 @@ def disable_account_ajax(request):
if account_action == 'disable':
user_account.account_status = UserStanding.ACCOUNT_DISABLED
context['message'] = _("Successfully disabled {}'s account").format(username)
log.info("%s disabled %s's account", request.user, username)
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.info("User %s disabled user %s's account", request.user.id, user.id)
else:
log.info("%s disabled %s's account", request.user, username)
elif account_action == 'reenable':
user_account.account_status = UserStanding.ACCOUNT_ENABLED
context['message'] = _("Successfully reenabled {}'s account").format(username)
log.info("%s reenabled %s's account", request.user, username)
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.info("User %s reenabled user %s's account", request.user.id, user.id)
else:
log.info("%s reenabled %s's account", request.user, username)
else:
context['message'] = _("Unexpected account status")
return JsonResponse(context, status=400)
Expand Down Expand Up @@ -847,11 +856,21 @@ def do_email_change_request(user, new_email, activation_key=None, secondary_emai

try:
ace.send(msg)
log.info("Email activation link sent to user [%s].", new_email)
except Exception:
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.info("Email activation link sent for user ID: [%s].", user.id)
else:
log.info("Email activation link sent to user [%s].", new_email)
except Exception as err:
from_address = configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL)
log.error('Unable to send email activation link to user from "%s"', from_address, exc_info=True)
raise ValueError(_('Unable to send email activation link. Please try again later.')) # pylint: disable=raise-missing-from # noqa: B904
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.error(
'Unable to send email activation link for user %s from a redacted address',
user.id,
exc_info=True,
)
else:
log.error('Unable to send email activation link to user from "%s"', from_address, exc_info=True)
raise ValueError(_('Unable to send email activation link. Please try again later.')) from err # lint-amnesty, pylint: disable=raise-missing-from

if not secondary_email_change_request:
# When the email address change is complete, a "edx.user.settings.changed" event will be emitted.
Expand Down Expand Up @@ -900,7 +919,7 @@ def activate_secondary_email(request, key):


@ensure_csrf_cookie
def confirm_email_change(request, key):
def confirm_email_change(request, key): # pylint: disable=too-many-statements
"""
User requested a new e-mail. This is called when the activation
link is clicked. We confirm with the old e-mail, and update
Expand Down Expand Up @@ -960,7 +979,10 @@ def confirm_email_change(request, key):
try:
ace.send(msg)
except Exception: # pylint: disable=broad-except
log.warning('Unable to send confirmation email to old address', exc_info=True)
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.warning('Unable to send confirmation email to old address for user %s', user.id, exc_info=True)
else:
log.warning('Unable to send confirmation email to old address', exc_info=True)
response = render_to_response("email_change_failed.html", {'email': user.email})
transaction.set_rollback(True)
return response
Expand All @@ -976,7 +998,10 @@ def confirm_email_change(request, key):
try:
ace.send(msg)
except Exception: # pylint: disable=broad-except
log.warning('Unable to send confirmation email to new address', exc_info=True)
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.warning('Unable to send confirmation email to new address for user %s', user.id, exc_info=True)
else:
log.warning('Unable to send confirmation email to new address', exc_info=True)
response = render_to_response("email_change_failed.html", {'email': user.email})
transaction.set_rollback(True)
return response
Expand Down
18 changes: 15 additions & 3 deletions lms/djangoapps/bulk_user_retirement/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""
import logging

from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import transaction
from rest_framework import permissions, status
Expand Down Expand Up @@ -56,11 +57,22 @@ def post(self, request, **kwargs): # pylint: disable=unused-argument
user_to_retire = User.objects.get(username=username)
with transaction.atomic():
create_retirement_request_and_deactivate_account(user_to_retire)
log.info(f'The user "{username}" has been added to the retirement pipeline \
by "{request.user}"')
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.info('User %s added to retirement pipeline by user %s',
user_to_retire.id,
request.user.id
)
else:
log.info('The user "%s" has been added to the retirement pipeline by "%s"',
username,
request.user,
)

except User.DoesNotExist:
log.exception(f'The user "{username}" does not exist.')
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.exception('A user does not exist for bulk retirement.')
else:
log.exception(f'The user "{username}" does not exist.')
failed_user_retirements.append(username)

except Exception as exc: # pylint: disable=broad-except
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ def send_ace_message(goal, session_id):
"""
user = goal.user
if not user.has_usable_password():
log.info(f'Goal Reminder User is disabled {user.username} course {goal.course_key}')
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.info(f'Goal Reminder User is disabled user ID {user.id} course {goal.course_key}')
else:
log.info(f'Goal Reminder User is disabled {user.username} course {goal.course_key}')
return False
try:
course = CourseOverview.get_from_id(goal.course_key)
Expand Down
10 changes: 7 additions & 3 deletions lms/djangoapps/courseware/model_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from abc import ABCMeta, abstractmethod
from collections import defaultdict, namedtuple

from django.conf import settings
from django.db import DatabaseError, IntegrityError, transaction
from opaque_keys.edx.asides import AsideUsageKeyV1, AsideUsageKeyV2
from opaque_keys.edx.block_types import BlockTypeKeyV1
Expand Down Expand Up @@ -404,9 +405,12 @@ def set_many(self, kv_dict):
self.user.username,
pending_updates
)
except DatabaseError:
log.exception("Saving user state failed for %s", self.user.username)
raise KeyValueMultiSaveError([]) # pylint: disable=raise-missing-from # noqa: B904
except DatabaseError as err:
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.exception("Saving user state failed for user ID %s", self.user.id)
else:
log.exception("Saving user state failed for %s", self.user.username)
raise KeyValueMultiSaveError([]) from err # lint-amnesty, pylint: disable=raise-missing-from
finally:
self._cache.update(pending_updates)

Expand Down
5 changes: 4 additions & 1 deletion lms/djangoapps/courseware/views/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1479,7 +1479,10 @@ def generate_user_cert(request, course_id):
return HttpResponseBadRequest(str(e))

if not is_course_passed(student, course):
log.info("User %s has not passed the course: %s", student.username, course_id)
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.info("User ID %s has not passed the course: %s", student.id, course_id)
else:
log.info("User %s has not passed the course: %s", student.username, course_id)
return HttpResponseBadRequest(_("Your certificate will be available when you pass the course."))

certificate_status = certs_api.certificate_downloadable_status(student, course.id)
Expand Down
18 changes: 12 additions & 6 deletions lms/djangoapps/instructor/views/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,13 +462,19 @@ def post(self, request, course_id): # pylint: disable=too-many-statements
warnings.append({
'username': username, 'email': email, 'response': warning_message
})
log.warning('email %s already exist', email)
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.warning('email for user %s already exist', user.id)
else:
log.warning('email %s already exist', email)
else:
log.info(
"user already exists with username '%s' and email '%s'",
username,
email
)
if settings.FEATURES['SQUELCH_PII_IN_LOGS']:
log.info('user already exists with user ID %s', user.id)
else:
log.info(
"user already exists with username '%s' and email '%s'",
username,
email
)

# enroll a user if it is not already enrolled.
if not is_user_enrolled_in_course(user, course_id):
Expand Down
Loading
Loading