Skip to content
Draft
Show file tree
Hide file tree
Changes from 7 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
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

[6.4.3]
--------
* feat: feat: Add JSON logging capability to integrated_channels

[6.4.2]
--------
* chore: upgrades 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__ = "6.4.2"
__version__ = "6.4.3"
105 changes: 52 additions & 53 deletions integrated_channels/blackboard/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import base64
import copy
import json
import logging
import time
from http import HTTPStatus
from urllib.parse import urljoin
Expand All @@ -17,9 +16,10 @@
from integrated_channels.blackboard.exporters.content_metadata import BLACKBOARD_COURSE_CONTENT_NAME
from integrated_channels.exceptions import ClientError
from integrated_channels.integrated_channel.client import IntegratedChannelApiClient
from integrated_channels.utils import generate_formatted_log, refresh_session_if_expired, stringify_and_store_api_record
from integrated_channels.logger import get_integrated_channels_logger, log_with_context
from integrated_channels.utils import refresh_session_if_expired, stringify_and_store_api_record

LOGGER = logging.getLogger(__name__)
LOGGER = get_integrated_channels_logger(__name__)

# TODO: Refactor candidate (duplication with canvas client)
GRADEBOOK_PATH = '/learn/api/public/v1/courses/{course_id}/gradebook/columns'
Expand Down Expand Up @@ -86,13 +86,15 @@ def create_content_metadata(self, serialized_data):
# course already exists!
msg_body = (f"Course already exists with course_id {external_id},"
f" and generated course_id: {course_id_generated}, not attempting creation")
LOGGER.warning(generate_formatted_log(
self.enterprise_configuration.channel_code(),
self.enterprise_configuration.enterprise_customer.uuid,
None,
external_id,
msg_body,
))
log_with_context(
LOGGER,
'WARNING',
channel_name=self.enterprise_configuration.channel_code(),
enterprise_customer_uuid=self.enterprise_configuration.enterprise_customer.uuid,
course_or_course_run_key=external_id,
message=msg_body,
status_code=HTTPStatus.NOT_MODIFIED.value
)
return HTTPStatus.NOT_MODIFIED.value, msg_body
else:
raise error
Expand Down Expand Up @@ -147,14 +149,13 @@ def update_content_metadata(self, serialized_data):
bb_content_id = content.get('id')

if not bb_content_id:
LOGGER.info(
generate_formatted_log(
self.enterprise_configuration.channel_code(),
self.enterprise_configuration.enterprise_customer.uuid,
None,
course_id,
'Blackboard integrated course content not found. Generating content.'
)
log_with_context(
LOGGER,
'INFO',
channel_name=self.enterprise_configuration.channel_code(),
enterprise_customer_uuid=self.enterprise_configuration.enterprise_customer.uuid,
course_or_course_run_key=course_id,
message='Blackboard integrated course content not found. Generating content.'
)
else:
course_content_delete_url = self.generate_course_content_delete_url(bb_course_id, bb_content_id)
Expand All @@ -179,14 +180,13 @@ def delete_content_metadata(self, serialized_data):
if not course_id:
return HTTPStatus.OK.value, 'Course:{} already removed.'.format(external_id)

LOGGER.info(
generate_formatted_log(
self.enterprise_configuration.channel_code(),
self.enterprise_configuration.enterprise_customer.uuid,
None,
course_id,
f'Deleting course with courseId: {course_id}'
)
log_with_context(
LOGGER,
'INFO',
channel_name=self.enterprise_configuration.channel_code(),
enterprise_customer_uuid=self.enterprise_configuration.enterprise_customer.uuid,
course_or_course_run_key=course_id,
message=f'Deleting course with courseId: {course_id}'
)
update_url = self.generate_course_update_url(course_id)
response = self._delete(update_url)
Expand Down Expand Up @@ -316,20 +316,23 @@ def _create_session(self):
self.expires_at,
)

def _formatted_message(self, msg):
return generate_formatted_log(
self.enterprise_configuration.channel_code(),
self.enterprise_configuration.enterprise_customer.uuid,
None,
None,
msg,
)

def _log_info(self, msg):
LOGGER.info(self._formatted_message(msg))
log_with_context(
LOGGER,
'INFO',
channel_name=self.enterprise_configuration.channel_code(),
enterprise_customer_uuid=self.enterprise_configuration.enterprise_customer.uuid,
message=msg
)

def _log_error(self, msg):
LOGGER.error(self._formatted_message(msg))
log_with_context(
LOGGER,
'ERROR',
channel_name=self.enterprise_configuration.channel_code(),
enterprise_customer_uuid=self.enterprise_configuration.enterprise_customer.uuid,
message=msg
)

def _get_oauth_access_token(self):
"""Fetch access token using refresh_token workflow from Blackboard
Expand Down Expand Up @@ -763,14 +766,12 @@ def _get_or_create_integrated_grade_column(self, bb_course_id, grade_column_name
more_pages_present = False

if current_page_count == PAGE_TRAVERSAL_LIMIT:
LOGGER.warning(
generate_formatted_log(
self.enterprise_configuration.channel_code(),
self.enterprise_configuration.enterprise_customer.uuid,
None,
None,
f'Max page limit hit while traversing blackboard API for course={external_id}'
)
log_with_context(
LOGGER,
'WARNING',
channel_name=self.enterprise_configuration.channel_code(),
enterprise_customer_uuid=self.enterprise_configuration.enterprise_customer.uuid,
message=f'Max page limit hit while traversing blackboard API for course={external_id}'
)

if not grade_column_id:
Expand Down Expand Up @@ -958,12 +959,10 @@ def cleanup_duplicate_assignment_records(self, courses):
"""
Not implemented yet.
"""
LOGGER.error(
generate_formatted_log(
self.enterprise_configuration.channel_code(),
self.enterprise_configuration.enterprise_customer.uuid,
None,
None,
"Blackboard integrated channel does not yet support assignment deduplication."
)
log_with_context(
LOGGER,
'ERROR',
channel_name=self.enterprise_configuration.channel_code(),
enterprise_customer_uuid=self.enterprise_configuration.enterprise_customer.uuid,
message="Blackboard integrated channel does not yet support assignment deduplication."
)
54 changes: 31 additions & 23 deletions integrated_channels/blackboard/exporters/learner_data.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
"""
Learner data exporter for Enterprise Integrated Channel Blackboard.
"""

from logging import getLogger

from django.apps import apps

from integrated_channels.catalog_service_utils import get_course_id_for_enrollment
from integrated_channels.integrated_channel.exporters.learner_data import LearnerExporter
from integrated_channels.utils import generate_formatted_log, parse_datetime_to_epoch_millis
from integrated_channels.logger import get_integrated_channels_logger, log_with_context
from integrated_channels.utils import parse_datetime_to_epoch_millis

LOGGER = getLogger(__name__)
LOGGER = get_integrated_channels_logger(__name__)


class BlackboardLearnerExporter(LearnerExporter):
Expand All @@ -33,15 +31,19 @@ def get_learner_data_records(
"""
enterprise_customer_user = enterprise_enrollment.enterprise_customer_user
if enterprise_customer_user.user_email is None:
LOGGER.debug(generate_formatted_log(
self.enterprise_configuration.channel_code(),
enterprise_customer_user.enterprise_customer.uuid,
enterprise_customer_user.user_id,
None,
('get_learner_data_records finished. No learner data was sent for this LMS User Id because '
'Blackboard User ID not found for [{name}]'.format(
name=enterprise_customer_user.enterprise_customer.name
))))
log_with_context(
LOGGER,
'DEBUG',
channel_name=self.enterprise_configuration.channel_code(),
enterprise_customer_uuid=enterprise_customer_user.enterprise_customer.uuid,
lms_user_id=enterprise_customer_user.user_id,
message=(
'get_learner_data_records finished. No learner data was sent for this LMS User Id because '
'Blackboard User ID not found for [{name}]'.format(
name=enterprise_customer_user.enterprise_customer.name
)
)
)
return None
percent_grade = kwargs.get('grade_percent', None)
blackboard_completed_timestamp = None
Expand Down Expand Up @@ -95,15 +97,21 @@ def get_learner_assessment_data_records(
"""
if enterprise_enrollment.enterprise_customer_user.user_email is None:
# We need an email to find the user on blackboard.
LOGGER.debug(generate_formatted_log(
self.enterprise_configuration.channel_code(),
enterprise_enrollment.enterprise_customer_user.enterprise_customer.uuid,
enterprise_enrollment.enterprise_customer_user.user_id,
enterprise_enrollment.course_id,
('get_learner_assessment_data_records finished. No learner data was sent for this LMS User Id because'
' Blackboard User ID not found for [{name}]'.format(
name=enterprise_enrollment.enterprise_customer_user.enterprise_customer.name
))))
log_with_context(
LOGGER,
'DEBUG',
channel_name=self.enterprise_configuration.channel_code(),
enterprise_customer_uuid=enterprise_enrollment.enterprise_customer_user.enterprise_customer.uuid,
lms_user_id=enterprise_enrollment.enterprise_customer_user.user_id,
course_or_course_run_key=enterprise_enrollment.course_id,
message=(
'get_learner_assessment_data_records finished. '
'No learner data was sent for this LMS User Id because'
' Blackboard User ID not found for [{name}]'.format(
name=enterprise_enrollment.enterprise_customer_user.enterprise_customer.name
)
)
)
return None

BlackboardLearnerAssessmentDataTransmissionAudit = apps.get_model(
Expand Down
Loading
Loading