Skip to content

Commit

Permalink
feat: expose enterprise_customer and enterprise_features in BFF respo…
Browse files Browse the repository at this point in the history
…nse (#597)
  • Loading branch information
adamstankiewicz authored Nov 22, 2024
1 parent adbd712 commit 32fa28f
Show file tree
Hide file tree
Showing 7 changed files with 318 additions and 130 deletions.
36 changes: 33 additions & 3 deletions enterprise_access/apps/api/v1/tests/test_bff_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ def setUp(self):
}
self.mock_enterprise_course_enrollments = []

self.expected_enterprise_customer = {
**self.mock_enterprise_customer,
'disable_search': False,
'show_integration_warning': True,
}

self.expected_customer_agreement = {
'uuid': self.mock_customer_agreement_uuid,
'available_subscription_catalogs': self.mock_customer_agreement.get('available_subscription_catalogs'),
Expand Down Expand Up @@ -126,7 +132,8 @@ def setUp(self):
}

# Mock base response data
self.mock_dashboard_route_response_data = {
self.mock_common_response_data = {
'enterprise_customer': self.expected_enterprise_customer,
'enterprise_customer_user_subsidies': {
'subscriptions': {
'customer_agreement': None,
Expand All @@ -139,9 +146,13 @@ def setUp(self):
},
},
},
'enterprise_course_enrollments': [],
'errors': [],
'warnings': [],
'enterprise_features': {'feature_flag': True},
}
self.mock_dashboard_route_response_data = {
**self.mock_common_response_data,
'enterprise_course_enrollments': [],
}

@ddt.data(
Expand Down Expand Up @@ -434,9 +445,21 @@ def test_dashboard_with_subscriptions_license_auto_apply(
'system_wide_role': SYSTEM_ENTERPRISE_LEARNER_ROLE,
'context': self.mock_enterprise_customer_uuid,
}])
mock_identity_provider = 'mock_idp' if identity_provider else None
mock_identity_providers = (
[
{
'provider_id': 'mock_idp',
'default_provider': True,
},
]
if identity_provider
else []
)
mock_enterprise_customer_with_auto_apply = {
**self.mock_enterprise_customer,
'identity_provider': identity_provider,
'identity_provider': mock_identity_provider,
'identity_providers': mock_identity_providers,
}
mock_enterprise_learner_response_data = {
**self.mock_enterprise_learner_response_data,
Expand Down Expand Up @@ -493,7 +516,14 @@ def test_dashboard_with_subscriptions_license_auto_apply(
}
expected_licenses = [expected_activated_subscription_license] if should_auto_apply else []
expected_response_data = self.mock_dashboard_route_response_data.copy()
expected_show_integration_warning = bool(identity_provider)
expected_response_data.update({
'enterprise_customer': {
**self.expected_enterprise_customer,
'identity_provider': mock_identity_provider,
'identity_providers': mock_identity_providers,
'show_integration_warning': expected_show_integration_warning,
},
'enterprise_customer_user_subsidies': {
'subscriptions': {
'customer_agreement': expected_customer_agreement,
Expand Down
4 changes: 3 additions & 1 deletion enterprise_access/apps/api/v1/views/bffs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,12 @@ def load_route_data_and_build_response(self, request, handler_class, response_bu

ordered_representation = OrderedDict(response_data)

# Remove errors and warnings from the response, and add them back at the end
# Remove errors/warnings & enterprise_features from the response, and add them back at the end
errors = ordered_representation.pop('errors', [])
warnings = ordered_representation.pop('warnings', [])
enterprise_features = ordered_representation.pop('enterprise_features', {})
ordered_representation['errors'] = errors
ordered_representation['warnings'] = warnings
ordered_representation['enterprise_features'] = enterprise_features

return dict(ordered_representation), status_code
62 changes: 30 additions & 32 deletions enterprise_access/apps/bffs/response_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ class BaseResponseBuilder:
response builders like `LearnerDashboardResponseBuilder` or `CourseResponseBuilder`.
"""

@property
def status_code(self):
"""
Returns the HTTP status code for the response from HandlerContext.
"""
return self.context.status_code

def __init__(self, context):
"""
Initializes the BaseResponseBuilder with a HandlerContext.
Expand All @@ -26,6 +33,7 @@ def __init__(self, context):
context (HandlerContext): The context object containing data, errors, and request information.
"""
self.context = context
self.response_data = {}

def build(self):
"""
Expand All @@ -35,25 +43,16 @@ def build(self):
Returns:
dict: A dictionary containing the response data.
"""
raise NotImplementedError("Subclasses must implement the `build` method.")
self.response_data['enterprise_customer'] = self.context.enterprise_customer
self.response_data['enterprise_features'] = self.context.enterprise_features
return self.response_data, self.status_code

def add_errors_warnings_to_response(self, response_data):
def add_errors_warnings_to_response(self):
"""
Adds any errors to the response data.
"""
response_data['errors'] = self.context.errors
response_data['warnings'] = self.context.warnings
return response_data

# TODO Revisit this function in ENT-9633 to determine if 200 is ok for a nested errored response
def get_status_code(self):
"""
Gets the current status code from the context.
Returns:
int: The HTTP status code.
"""
return self.context.status_code
self.response_data['errors'] = self.context.errors
self.response_data['warnings'] = self.context.warnings


class BaseLearnerResponseBuilder(BaseResponseBuilder, BaseLearnerDataMixin):
Expand All @@ -64,7 +63,7 @@ class BaseLearnerResponseBuilder(BaseResponseBuilder, BaseLearnerDataMixin):
for building responses across all learner-focused page routes.
"""

def common_response_logic(self, response_data=None):
def common_response_logic(self):
"""
Applies common response logic for learner-related responses.
Expand All @@ -74,12 +73,7 @@ def common_response_logic(self, response_data=None):
Returns:
dict: The modified response data with common logic applied.
"""
if not response_data:
response_data = {}

response_data['enterprise_customer_user_subsidies'] = self.enterprise_customer_user_subsidies

return response_data
self.response_data['enterprise_customer_user_subsidies'] = self.enterprise_customer_user_subsidies

def build(self):
"""
Expand All @@ -90,14 +84,16 @@ def build(self):
Returns:
dict: A tuple containing the base response data and status code.
"""
super().build()

# Initialize response data with common learner-related logic
response_data = self.common_response_logic()
self.common_response_logic()

# Add any errors, etc.
response_data = self.add_errors_warnings_to_response(response_data)
self.add_errors_warnings_to_response()

# Return the response data and status code
return response_data, self.get_status_code()
return self.response_data, self.status_code


class LearnerDashboardResponseBuilder(BaseLearnerResponseBuilder, LearnerDashboardDataMixin):
Expand All @@ -118,29 +114,31 @@ def build(self):
dict: A tuple containing the learner dashboard serialized response data and status code.
"""
# Build common response data
response_data, __ = super().build()
super().build()

# Add specific fields related to the learner dashboard
response_data.update({
self.response_data.update({
'enterprise_course_enrollments': self.enterprise_course_enrollments,
})

# Add any errors and warnings to the response
response_data = self.add_errors_warnings_to_response(response_data)
self.add_errors_warnings_to_response()

# Serialize and validate the response
try:
serializer = LearnerDashboardResponseSerializer(data=response_data)
serializer = LearnerDashboardResponseSerializer(data=self.response_data)
serializer.is_valid(raise_exception=True)
serialized_data = serializer.validated_data

# Return the response data and status code
return serialized_data, self.get_status_code()
return serialized_data, self.status_code
except Exception as exc: # pylint: disable=broad-except
logger.exception('Could not serialize the response data.')
self.context.add_error(
user_message='An error occurred while processing the response data.',
developer_message=f'Could not serialize the response data. Error: {exc}',
)
response_data = self.add_errors_warnings_to_response(response_data)
return response_data, self.get_status_code()
self.add_errors_warnings_to_response()
serializer = LearnerDashboardResponseSerializer(self.response_data)
serialized_data = serializer.data
return serialized_data, self.status_code
Loading

0 comments on commit 32fa28f

Please sign in to comment.