
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.

Requires #5170
Overview
As part of this issue we will finally transfer a channel to be part of the Community Library. From the technical implementation perspective, Community Library channels will be identified as channel records in the kolibri_public app models where the public field is set to false. This means that the approved channel version will be mapped to a channel within the kolibri_public application models.
Prerrequisites
- Understand the Studio channel publishing workflow.
- Understand how channel databases are stored in Studio.
- Understand how a channel is made public.
- Understand how the channel changes mechanism works.
Technical requirements
Upon approval of a submission, a new asynchronous task should be enqueued to map the approved channel version's database to the kolibri_public models.
To handle this new asynchronous task, we will leverage our existing changes architecture and integrate this process as a new channel change type, named ADDED_TO_COMMUNITY_LIBRARY.
- We will add a new
ADDED_TO_COMMUNITY_LIBRARY change type in the sync/constants.py file, and include this new change in the ALL_CHANGES array.
- This new
ADDED_TO_COMMUNITY_LIBRARY change will be enqueued immediately after an admin has approved a submission in the resolution action in the Community Library Submission Viewset. To enqueue this task, we can:
- Create a new
generate_add_to_community_library_event function in viewsets/sync/utils.py that receives the key, the channel_version, and an optional categories and countries arguments. These optional arguments will then be populated with data from the approved submission.
- Within the
submission viewset action, we can then create a new ADDED_TO_COMMUNITY_LIBRARY change using the Change.create_change method where the change will be the one returned from the generate_add_to_community_library_event function, and its author will be set to the user who approved the submission.
- Finally we will call the
apply_channel_changes_task.fetch_or_enqueue method that will enqueue the apply_channel_changes_task for this change to be applied. In the publish channel api you can see an example of how to create a new event and subsequently enqueue this task.
- This new change will just be allowed to be created on the server side. So adding a new
ADDED_TO_COMMUNITY_LIBRARY change through the sync viewset should not be allowed.
- We can achieve this by adding a new
SERVER_ONLY_CHANGES constant in the viewsets/sync/constants.py file. Any change included in SERVER_ONLY_CHANGES arriving via the sync endpoint will then be rejected.
- Now, to support the new metadata introduced by
CommunityLibrarySubmission. We will need to create two new fields in the ChannelMetadata model of the kolibri_public app: categories and countries.
- To enable filtering by
categories, we will need to add bitmap fields to the ChannelMetadata model. However, this will be part of a subsequent issue; let's not focus on it for now.
- In the ChannelViewset we will add a new
add_to_community_library_from_changes method that will call an add_to_community_library method (description of this method below) for each change. Then we will map the new ADDED_TO_COMMUNITY_LIBRARY change to the add_to_community_library_from_changes method in the apply_changes function event handlers. With this, we will be able to apply ADDED_TO_COMMUNITY_LIBRARY changes.
- The
add_to_community_library method should receive the channel ID, the channel version to be added to the Community Library, and the categories and countries that will be added to the community library, the categories and the countries that will be added to the kolibri_public ChannelMetadata instance.
- To export the channel to the
kolibri_public models, we will reuse the logic that we have in the _export_channel method of the export_channels_to_kolibri_public command.
- To reuse this
_export_channel method across the command and the sync changes task, we will move this logic to a new export_channel_to_kolibri_public file in the kolibri_public/utils folder, which will define the export_channel_to_kolibri_public function.
- We should modify this
export_channel_to_kolibri_public function to accommodate the new requirements for adding a channel to the Community Library. Specifically, this function should now receive channel_id as a required argument, and channel_version=None, public=True, categories=None, and countries=None as optional arguments. Subsequently, we should modify the ChannelMapper class to receive all these new values as optional arguments in its constructor method.
- Within the ChannelMapper's run method we call the
set_channel_metadata_fields util function to annotate additional metadata that this channel will have in the ChannelMetadata model. As we are now introducing categories and countries to this model, we should modify the set_channel_metadata_fields function to :
- Add the calculation of the
categories field taking into account both: the included channel categories (i.e. querying the categories of all channel contentnodes, similar to what we do for included languages), and the categories obtained from the submission. Included categories can also be obtained from the published_data content curation channel field, but this field will not be available for older channels, so lets replicate what we do for the included_languages field.
- Add the countries list to the channel.
- The
export_channels_to_kolibri_public command should use this utility function in its handler method, calling it just passing the channel_id parameter.
- The
add_to_community_library channel viewset method should call this utility function with all optional parameters set.
- Finally, unit tests should be added to cover at least the following scenarios:
- After a submission has been approved, a new change event is created in the changes model, and the apply channel changes task has been enqueued.
- If a submission is rejected, no new change event is created in the changes model.
- Test that the new
ADDED_TO_COMMUNITY_LIBRARY is not applied if we send it through the sync endpoint.
- Test that the channel apply changes task is instantiating the ChannelMapper object with the correct arguments, and its calling the channelMapper.run afterwards.
- Test that a exception is thrown if we try adding a
ADDED_TO_COMMUNITY_LIBRARY change with a non-existing channel version database.
- Add new tests to the ChannelMapper test case to test that the
categories field is being set correctly to the kolibri_public channel.
- Add new tests to the ChannelMapper test case to test that the
countries field is being set correctly to the kolibri_public channel.
Acceptance criteria
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.
Requires #5170
Overview
As part of this issue we will finally transfer a channel to be part of the Community Library. From the technical implementation perspective, Community Library channels will be identified as channel records in the
kolibri_publicapp models where thepublicfield is set tofalse. This means that the approved channel version will be mapped to a channel within thekolibri_publicapplication models.Prerrequisites
Technical requirements
Upon approval of a submission, a new asynchronous task should be enqueued to map the approved channel version's database to the
kolibri_publicmodels.To handle this new asynchronous task, we will leverage our existing changes architecture and integrate this process as a new channel change type, named
ADDED_TO_COMMUNITY_LIBRARY.ADDED_TO_COMMUNITY_LIBRARYchange type in the sync/constants.py file, and include this new change in theALL_CHANGESarray.ADDED_TO_COMMUNITY_LIBRARYchange will be enqueued immediately after an admin has approved a submission in theresolutionaction in the Community Library Submission Viewset. To enqueue this task, we can:generate_add_to_community_library_eventfunction in viewsets/sync/utils.py that receives thekey, thechannel_version, and an optionalcategoriesandcountriesarguments. These optional arguments will then be populated with data from the approved submission.submissionviewset action, we can then create a newADDED_TO_COMMUNITY_LIBRARYchange using the Change.create_change method where the change will be the one returned from thegenerate_add_to_community_library_eventfunction, and its author will be set to the user who approved the submission.apply_channel_changes_task.fetch_or_enqueuemethod that will enqueue theapply_channel_changes_taskfor this change to be applied. In the publish channel api you can see an example of how to create a new event and subsequently enqueue this task.ADDED_TO_COMMUNITY_LIBRARYchange through the sync viewset should not be allowed.SERVER_ONLY_CHANGESconstant in the viewsets/sync/constants.py file. Any change included inSERVER_ONLY_CHANGESarriving via the sync endpoint will then be rejected.CommunityLibrarySubmission. We will need to create two new fields in the ChannelMetadata model of thekolibri_publicapp:categoriesandcountries.categories, we will need to add bitmap fields to theChannelMetadatamodel. However, this will be part of a subsequent issue; let's not focus on it for now.add_to_community_library_from_changesmethod that will call anadd_to_community_librarymethod (description of this method below) for each change. Then we will map the newADDED_TO_COMMUNITY_LIBRARYchange to theadd_to_community_library_from_changesmethod in the apply_changes function event handlers. With this, we will be able to applyADDED_TO_COMMUNITY_LIBRARYchanges.add_to_community_librarymethod should receive the channel ID, the channel version to be added to the Community Library, and the categories and countries that will be added to the community library, the categories and the countries that will be added to the kolibri_public ChannelMetadata instance.kolibri_publicmodels, we will reuse the logic that we have in the_export_channelmethod of the export_channels_to_kolibri_public command._export_channelmethod across the command and the sync changes task, we will move this logic to a newexport_channel_to_kolibri_publicfile in thekolibri_public/utilsfolder, which will define theexport_channel_to_kolibri_publicfunction.export_channel_to_kolibri_publicfunction to accommodate the new requirements for adding a channel to the Community Library. Specifically, this function should now receivechannel_idas a required argument, andchannel_version=None,public=True,categories=None, andcountries=Noneas optional arguments. Subsequently, we should modify the ChannelMapper class to receive all these new values as optional arguments in its constructor method.set_channel_metadata_fieldsutil function to annotate additional metadata that this channel will have in the ChannelMetadata model. As we are now introducingcategoriesandcountriesto this model, we should modify the set_channel_metadata_fields function to :categoriesfield taking into account both: the included channel categories (i.e. querying the categories of all channel contentnodes, similar to what we do for included languages), and the categories obtained from the submission. Included categories can also be obtained from thepublished_datacontent curation channel field, but this field will not be available for older channels, so lets replicate what we do for the included_languages field.export_channels_to_kolibri_publiccommand should use this utility function in its handler method, calling it just passing thechannel_idparameter.add_to_community_librarychannel viewset method should call this utility function with all optional parameters set.ADDED_TO_COMMUNITY_LIBRARYis not applied if we send it through the sync endpoint.ADDED_TO_COMMUNITY_LIBRARYchange with a non-existing channel version database.categoriesfield is being set correctly to thekolibri_publicchannel.countriesfield is being set correctly to thekolibri_publicchannel.Acceptance criteria
ADDED_TO_COMMUNITY_LIBRARYchange is enqueued after the submission was approved.categoriesandcountriesfields have been added to thekolibri_public'sChannelMetadatamodel.add_to_community_library_from_changesmethod is added to the channel viewset and mapped to the apply changes event handlers.export_channel_to_kolibri_publicfunction is created to support the apply changes task, and the existingexport_channels_to_kolibri_publiccommand.kolibri_publicmodels after the task was run.