From 2ee7e0aa61c3391c04c40f951aeb39c4575fd8a4 Mon Sep 17 00:00:00 2001 From: Alexander J Sheehan Date: Thu, 6 Jul 2023 17:56:52 +0000 Subject: [PATCH] feat: discovery work into implementing integrated skills content --- .../exporters/content_metadata.py | 60 ++++++++++++++++++- .../integrated_channel/models.py | 44 ++++++++++++++ .../transmitters/content_metadata.py | 31 +++++++++- 3 files changed, 133 insertions(+), 2 deletions(-) diff --git a/integrated_channels/integrated_channel/exporters/content_metadata.py b/integrated_channels/integrated_channel/exporters/content_metadata.py index d156c74caa..262bad8cf0 100644 --- a/integrated_channels/integrated_channel/exporters/content_metadata.py +++ b/integrated_channels/integrated_channel/exporters/content_metadata.py @@ -454,7 +454,7 @@ def export(self, **kwargs): self.enterprise_customer.enterprise_customer_catalogs.all() # a maximum number of changes/payloads to export at once - # default to something huge to simplifly logic, the max system int size + # default to something huge to simplify logic, the max system int size max_payload_count = kwargs.get('max_payload_count', sys.maxsize) self._log_info( @@ -571,6 +571,64 @@ def export(self, **kwargs): f'{create_payload}, update_payload: {update_payload}, delete_payload: {delete_payload}' ) + # Above ^ ensure skill metadata persists in the 3 payloads after fetching content metadata + + # Buckets returned + + # ----*skills*---- + # create skills + # - list of skill audits, marked for create + # update skills + # - list of skill audits, marked for update + # delete skills + # - list of skill audits, marked for delete + + # ----*skill relations*---- + # add relation between content and skill + # - dict { skill_name : [content_key, ... ] } + # remove relation between content and skill + # - dict { skill_name : [content_key, ... ] } + + # For each item in update_payload + # - Grab all skill audits associated with the item's content key + # - for each found skill audit, + # - look for it in the metadata of the item_to_update item + # - if not there + # - add skill name/content key to the remove skill relations payload + # - if the skill audit's associated content keys len is 1 + # - add the skill to the delete payload + # - if there + # - update the skill audit record with the item's metadata + # - if change add the skill audit to the update skills payload + # - remember the skill name of the found update payload + # - for each skill in the item's metadata that wasn't found in the skill audit records + # - create the skill audit + # - add the skill audit to the create skill payload + # - add the skill/content key to the add relations payload + + # Iterate over items_to_create and get_or_create a skills audit under the config + customer config and write the content + # key to the audit's list of linked skills + # For each item in create payload + # - Grab all skills listed in the item's metadata + # - for each skill audit + # - add the skill name/content key to the add relations payload + # - for any skills listed in the item's metadata that weren't found in the skill audits + # - create a new skill audit record, mark for create + # - add the audit to the create skill payload + + # Iterate over items_to_delete and filter for skill audits that contain the item's content key within the records associated + # content keys set. + # For each item in delete payload + # - Grab all audits associated with the item's content key + # - for each found skill audit + # - if the skill audit's content keys set is 1 + # - add the skill audit to the delete payload + # - add the skill/content key to the remove skill relations payload + + + # Below add the skill metadata related payloads to the list of returned objects (either as one combined object or 3 separate) + # { create : create_payload, update : update_payload, delete : delete_payload }, { add : relations_add_payload, remove : relations_remove_payload } + # collections of ContentMetadataItemTransmission objects return create_payload, update_payload, delete_payload diff --git a/integrated_channels/integrated_channel/models.py b/integrated_channels/integrated_channel/models.py index 753ed24ec8..b78f400880 100644 --- a/integrated_channels/integrated_channel/models.py +++ b/integrated_channels/integrated_channel/models.py @@ -393,6 +393,13 @@ def transmit_content_metadata(self, user): transmitter = self.get_content_metadata_transmitter() transmitter.transmit(*exporter.export()) + # Instead of ^ + + # create, update, delete, skills_metadata, relations_metadata = exporter.export() + # transmitter.transmit(create, update, delete) + # transmitter.transmit_skills(skills_metadata) + # transmitter.transmit_skill_associations(relations_metadata) + def transmit_single_subsection_learner_data(self, **kwargs): """ Transmit a single subsection learner data record to the integrated channel. @@ -603,6 +610,43 @@ def __repr__(self): """ return self.__str__() +# class SkillMetadataItemTransmission(TimeStampedModel): +# (PK?) +# skill_name = models.CharField(...) + +# --------*Metadata*---------- +# description = models.CharField(...) +# category = JSONField(...) +# subcategory = JSONField(...) + +# --------*Relations*--------- +# associated_catalog_keys = models.ManyToManyField( +# ContentMetadataItemTransmission +# ) + +# --------*Remote API*-------- +# remote_deleted_at = models.DateTimeField( +# help_text='Date when the content transmission was deleted in the remote API', +# blank=True, +# null=True +# ) +# remote_created_at = models.DateTimeField( +# help_text='Date when the content transmission was created in the remote API', +# blank=True, +# null=True +# ) +# remote_updated_at = models.DateTimeField( +# help_text='Date when the content transmission was last updated in the remote API', +# blank=True, +# null=True +# ) +# api_record = models.OneToOneField( +# ApiResponseRecord, +# blank=True, +# null=True, +# on_delete=models.CASCADE, +# help_text=_('Data pertaining to the transmissions API request response.') +# ) class ContentMetadataItemTransmission(TimeStampedModel): """ diff --git a/integrated_channels/integrated_channel/transmitters/content_metadata.py b/integrated_channels/integrated_channel/transmitters/content_metadata.py index 6f3bca3701..ce265cbac1 100644 --- a/integrated_channels/integrated_channel/transmitters/content_metadata.py +++ b/integrated_channels/integrated_channel/transmitters/content_metadata.py @@ -37,6 +37,18 @@ def __init__(self, enterprise_configuration, client=IntegratedChannelApiClient): enterprise_configuration=enterprise_configuration, client=client ) + # self._transmit_skill_create = functools.partial( + # ... + # self._transmit_skill_update = functools.partial( + # ... + # self._transmit_skill_delete = functools.partial( + # ... + + # self._transmit_skill_association_create = functools.partial( + # ... + # self._transmit_skill_association_delete = functools.partial( + # ... + self._transmit_create = functools.partial( self._transmit_action, client_method=self.client.create_content_metadata, @@ -83,6 +95,15 @@ def _log_info_for_each_item_map(self, item_map, msg): course_or_course_run_key=content_id ) + # def transmit_skills(self, skill_metadata): + # _transmit_skill_create(skill_metadata['create']) + # _transmit_skill_update(skill_metadata['update']) + # _transmit_skill_delete(skill_metadata['delete']) + + # def transmit_skill_associations(self, relations_metadata): + # _transmit_skill_association_create(relations_metadata['create']) + # _transmit_skill_association_delete(relations_metadata['delete']) + def transmit(self, create_payload, update_payload, delete_payload): """ Transmit content metadata items to the integrated channel. Save or update content metadata records according to @@ -125,6 +146,14 @@ def _serialize_items(self, channel_metadata_items): sort_keys=True ).encode('utf-8') + # def _transmit_skill_action(self, skill_payload, client_method, action_name): + # - chunk payload + # - serialize payload + # - invoke client method + # - capture client response + # - update audit record with api response (text, status) + # - remove mark + def _transmit_action(self, content_metadata_item_map, client_method, action_name): # pylint: disable=too-many-statements """ Do the work of calling the appropriate client method, saving the results, and updating @@ -136,7 +165,7 @@ def _transmit_action(self, content_metadata_item_map, client_method, action_name self.enterprise_configuration.channel_code() ) - # If we're deleting, fetch all orphaned, uneresolved content transmissions + # If we're deleting, fetch all orphaned, unresolved content transmissions is_delete_action = action_name == 'delete' if is_delete_action: OrphanedContentTransmissions = apps.get_model(