Skip to content

Commit

Permalink
chore: Additional logging and exception handling
Browse files Browse the repository at this point in the history
  • Loading branch information
brobro10000 committed Jan 31, 2024
1 parent 197af37 commit 937d012
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class LearnerContentAssignmentActionSerializer(serializers.ModelSerializer):
"""
A read-only Serializer for responding to requests for ``LearnerContentAssignmentAction`` records.
"""

class Meta:
model = LearnerContentAssignmentAction
fields = [
Expand Down Expand Up @@ -181,10 +182,12 @@ class LearnerContentAssignmentNudgeRequestSerializer(serializers.Serializer):
"""
assignment_uuids = serializers.ListField(
child=serializers.UUIDField(),
allow_empty=False
allow_empty=False,
help_text="A list of executive education assignment uuids associated with an assignment configuration"
)
days_before_course_start_date = serializers.IntegerField(
min_value=1
min_value=1,
help_text="The number days ahead of a course start_date we want to send a nudge email for"
)


Expand All @@ -196,14 +199,25 @@ class LearnerContentAssignmentNudgeResponseSerializer(serializers.Serializer):
"""
nudged_assignment_uuids = serializers.ListField(
child=serializers.UUIDField(),
allow_empty=False
allow_empty=False,
help_text="A list of uuids that have been sent to the celery task to nudge"
)
unnudged_assignment_uuids = serializers.ListField(
child=serializers.UUIDField(),
allow_empty=True
allow_empty=True,
help_text="A list of uuids that have not been sent to the celery task to nudge"
)


class LearnerContentAssignmentNudgeHTTP422ErrorSerializer(serializers.Serializer):
"""
Response serializer for nudge endpoint 422 errors.
For view: LearnerContentAssignmentAdminViewSet.nudge
"""
error_message = serializers.CharField()


class ContentMetadataForAssignmentSerializer(serializers.Serializer):
"""
Serializer to help return additional content metadata for assignments. These fields should
Expand Down
72 changes: 52 additions & 20 deletions enterprise_access/apps/api/v1/tests/test_assignment_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ def test_cancel(self, mock_send_cancel_email):
@mock.patch('enterprise_access.apps.content_assignments.tasks.send_exec_ed_enrollment_warmer.delay')
def test_nudge_happy_path(self, mock_send_nudge_email, mock_content_metadata_for_assignments):
"""
Test that the cancel view cancels the assignment and returns an appropriate response with 200 status code and
Test that the nudge view nudges the assignment and returns an appropriate response with 200 status code and
the expected results of serialization.
"""
# Set the JWT-based auth to an operator.
Expand Down Expand Up @@ -682,56 +682,88 @@ def test_nudge_happy_path(self, mock_send_nudge_email, mock_content_metadata_for
'days_before_course_start_date': 14
}

expected_response = {
"nudged_assignment_uuids": [str(self.assignment_accepted.uuid)],
"unnudged_assignment_uuids": []
}

response = self.client.post(nudge_url, query_params)

# Verify the API response.
assert response.status_code == status.HTTP_200_OK
assert response.json() == expected_response

mock_send_nudge_email.assert_called_once_with(self.assignment_accepted.uuid, 14)

@mock.patch('enterprise_access.apps.content_assignments.api.get_content_metadata_for_assignments')
@mock.patch('enterprise_access.apps.content_assignments.tasks.send_exec_ed_enrollment_warmer.delay')
def test_nudge_allocated_assignment(self, mock_send_nudge_email, mock_content_metadata_for_assignments):
def test_nudge_allocated_assignment(self, mock_send_nudge_email):
"""
Test that the cancel view cancels the assignment and returns an appropriate response with 200 status code and
Test that the nudge view doesn't nudge the assignment and
returns an appropriate response with 422 status code and
the expected results of serialization.
"""
# Set the JWT-based auth to an operator.
self.set_jwt_cookie([
{'system_wide_role': SYSTEM_ENTERPRISE_OPERATOR_ROLE, 'context': str(TEST_ENTERPRISE_UUID)}
])

start_date = timezone.now().replace(microsecond=0) + timezone.timedelta(days=14)
end_date = timezone.now().replace(microsecond=0) + timezone.timedelta(days=180)
enrollment_end = timezone.now().replace(microsecond=0) - timezone.timedelta(days=5)
# Call the nudge endpoint.
nudge_kwargs = {
'assignment_configuration_uuid': self.assignment_configuration.uuid,
}
nudge_url = reverse('api:v1:admin-assignments-nudge', kwargs=nudge_kwargs)
query_params = {
'assignment_uuids': [str(self.assignment_allocated_post_link.uuid)],
'days_before_course_start_date': 14
}

# Mock content metadata for assignment
mock_content_metadata_for_assignments.return_value = {
'edX+edXPrivacy101': {
'key': 'edX+edXAccessibility101',
'normalized_metadata': {
'start_date': start_date.strftime("%Y-%m-%dT%H:%M:%SZ"),
'end_date': end_date.strftime("%Y-%m-%dT%H:%M:%SZ"),
'enroll_by_date': enrollment_end.strftime("%Y-%m-%d %H:%M"),
'content_price': 321,
},
'course_type': 'executive-education-2u',
}
response = self.client.post(nudge_url, query_params)

expected_response = {
"error_message": "Could not process the nudge email(s) for assignment_configuration_uuid: {0}"
.format(self.assignment_configuration.uuid),
}

# Verify the API response.
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
assert response.json() == expected_response

mock_send_nudge_email.assert_not_called()

@mock.patch('enterprise_access.apps.content_assignments.tasks.send_exec_ed_enrollment_warmer.delay')
def test_nudge_no_assignments(self, mock_send_nudge_email):
"""
Test that the nudge view doesn't nudge the assignment and
returns an appropriate response with 422 status code and
the expected results of serialization.
"""
# Set the JWT-based auth to an operator.
self.set_jwt_cookie([
{'system_wide_role': SYSTEM_ENTERPRISE_OPERATOR_ROLE, 'context': str(TEST_ENTERPRISE_UUID)}
])

# Call the nudge endpoint.
nudge_kwargs = {
'assignment_configuration_uuid': self.assignment_configuration.uuid,
}
nudge_url = reverse('api:v1:admin-assignments-nudge', kwargs=nudge_kwargs)

query_params = {
'assignment_uuids': [str(self.assignment_allocated_post_link.uuid)],
'assignment_uuids': [str(uuid4())],
'days_before_course_start_date': 14
}

response = self.client.post(nudge_url, query_params)

expected_response = {
"error_message": "The list of assignments provided are not "
"associated to the assignment_configuration_uuid: {0}"
.format(self.assignment_configuration.uuid)
}

# Verify the API response.
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
assert response.json() == expected_response

mock_send_nudge_email.assert_not_called()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from enterprise_access.apps.api import filters, serializers, utils
from enterprise_access.apps.api.serializers.content_assignments.assignment import (
LearnerContentAssignmentActionRequestSerializer,
LearnerContentAssignmentNudgeHTTP422ErrorSerializer,
LearnerContentAssignmentNudgeRequestSerializer,
LearnerContentAssignmentNudgeResponseSerializer
)
Expand Down Expand Up @@ -357,7 +358,7 @@ def remind_all(self, request, *args, **kwargs):
parameters=None,
responses={
status.HTTP_200_OK: LearnerContentAssignmentNudgeResponseSerializer,
status.HTTP_422_UNPROCESSABLE_ENTITY: None,
status.HTTP_422_UNPROCESSABLE_ENTITY: LearnerContentAssignmentNudgeHTTP422ErrorSerializer,
}
)
@permission_required(CONTENT_ASSIGNMENT_ADMIN_WRITE_PERMISSION, fn=assignment_admin_permission_fn)
Expand All @@ -382,6 +383,14 @@ def nudge(self, request, *args, **kwargs):
)
days_before_course_start_date = serializer.data['days_before_course_start_date']
try:
if len(assignments) == 0:
error_message = (
"The list of assignments provided are not associated to the assignment_configuration_uuid: {0}"
.format(assignment_configuration_uuid)
)
return Response(
data={"error_message": error_message}, status=status.HTTP_422_UNPROCESSABLE_ENTITY
)
result = assignments_api.nudge_assignments(
assignments,
assignment_configuration_uuid,
Expand All @@ -391,4 +400,11 @@ def nudge(self, request, *args, **kwargs):
response_serializer.is_valid(raise_exception=True)
return Response(data=response_serializer.data, status=status.HTTP_200_OK)
except Exception: # pylint: disable=broad-except
return Response(status=status.HTTP_422_UNPROCESSABLE_ENTITY)
error_message = (
"Could not process the nudge email(s) for assignment_configuration_uuid: {0}"
.format(assignment_configuration_uuid)
)
return Response(
data={"error_message": error_message},
status=status.HTTP_422_UNPROCESSABLE_ENTITY
)
1 change: 1 addition & 0 deletions enterprise_access/apps/content_assignments/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@ def nudge_assignments(assignments, assignment_configuration_uuid, days_before_co
# Declare our expected response output
nudged_assignment_uuids = []
unnudged_assignment_uuids = []

# Isolate assignment configuration metadata and associated assignments
assignment_configuration = AssignmentConfiguration.objects.get(uuid=assignment_configuration_uuid)
subsidy_access_policy = assignment_configuration.subsidy_access_policy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def get_human_readable_date(datetime_string, output_pattern=DEFAULT_STRFTIME_PAT
return None


def parse_datetime_string(datetime_string, **set_to_utc):
def parse_datetime_string(datetime_string, set_to_utc=False):
"""
Given a datetime string value from some content metadata record,
parse it into a datetime object.
Expand Down
5 changes: 5 additions & 0 deletions enterprise_access/apps/content_assignments/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,11 @@ def send_exec_ed_enrollment_warmer(assignment_uuid, days_before_course_start_dat

campaign_uuid = settings.BRAZE_ASSIGNMENT_NUDGE_EXEC_ED_ACCEPTED_ASSIGNMENT_CAMPAIGN

logger.info(
f'Sending braze campaign nudge reminder at '
f'days_before_course_start_date={days_before_course_start_date} '
f'uuid={campaign_uuid} message for assignment {assignment}'
)
campaign_sender.send_campaign_message(
braze_trigger_properties,
campaign_uuid,
Expand Down

0 comments on commit 937d012

Please sign in to comment.