...
Create New Project : Define Scope and Schedule
The Program Scope tab (see: "Define Scope and Schedule" in [3] (Google Slide)) is to include the ability to select target collection/questionSet and target content type(s)/question type(s). The contents of the
Select Target Collection
dropdown are fetched from thecollectionCategories
array, which must be expanded to include the objects of typequestionSet
.
Code Block language js // Old Code setFrameworkDataToProgram() { this.collectionCategories = _.get(this.cacheService.get(this.userService.hashTagId), 'collectionPrimaryCategories'); const channelCats = _.get(this.cacheService.get(this.userService.hashTagId), 'primaryCategories'); this.programScope['targetPrimaryCategories'] = []; const channeltargetObjectTypeGroup = _.groupBy(channelCats, 'targetObjectType'); if (this.enableQuestionSetEditor === 'true') { const questionSetCategories = _.get(channeltargetObjectTypeGroup, 'QuestionSet'); this.programScope['targetPrimaryCategories'] = _.map(questionSetCategories, 'name'); this.programScope['targetPrimaryObjects'] = questionSetCategories; } // New Code setFrameworkDataToProgram() { this.tempCollectionCategories = _.get(this.cacheService.get(this.userService.hashTagId), 'collectionPrimaryCategories'); const channelCats = _.get(this.cacheService.get(this.userService.hashTagId), 'primaryCategories'); this.programScope['targetPrimaryCategories'] = []; const channeltargetObjectTypeGroup = _.groupBy(channelCats, 'targetObjectType'); if (this.enableQuestionSetEditor === 'true') { const questionSetCategories = _.get(channeltargetObjectTypeGroup, 'QuestionSet'); this.programScope['targetPrimaryCategories'] = _.map(questionSetCategories, 'name'); this.programScope['targetPrimaryObjects'] = questionSetCategories; // Include QuestionSets inside collection categories this.collectionCategories = _.concat(this.tempCollectionCategories || [], this.programScope['targetPrimaryCategories']); }
Based on a mapping defined via a system-level configuration, the values in the dependent dropdown
Select Required Assets
will be populated. The mapping may resemble the following:
Mapping ConfigurationCode Block language json [ { "identifier": "obj-cat:content-playlist_collection_all", "name": "Content Playlist", "targetObjectType": "Collection", "associatedAssetTypes": ["Content"] }, { "identifier": "obj-cat:demo-practice-question-set_questionset_all", "name": "Demo Practice Question Set", "targetObjectType": "QuestionSet", "associatedAssetTypes": ["Question", "QuestionSet"] }, { "identifier": "obj-cat:digital-textbook_collection_all", "name": "Digital Textbook", "targetObjectType": "Collection", "associatedAssetTypes": ["Content"] }, { "identifier": "obj-cat:professional-development-course_collection_all", "name": "Professional Development Course", "targetObjectType": "Collection", "associatedAssetTypes": ["Content"] }, { "identifier": "obj-cat:question-paper_collection_all", "name": "Question Paper", "targetObjectType": "Collection", "associatedAssetTypes": ["Content"] } ]
Based on the selected target collection value (
"Question Paper"
or"Demo Practice Question Set"
) and the above mapping, the values in theSelect Target Asset
dropdown will be updatedA new variable may be introduced in the program definition,
program.targetCollectionType
, which may be one of["Collection", "QuestionSet"]
(Detailed at the end)The category definition of the selected target collection may be fetched through the
getCategoryDefinition
function via the following API call:POST
/content/object/category/definition/v1/read?fields=objectMetadata,forms,name
Code Block { "request": { "objectCategoryDefinition": { "objectType": "QuestionSet", "name": "Demo Practice Question Set", "channel": "" } } }
Create New Project: Select/Create Objects
On advancing to the next tab:
A draft project will be created via the following API:
POST
content/program/v1/create
Code Block language json { "request": { "name": "Test 1", "description": "Descr", "nomination_enddate": null, "shortlisting_enddate": null, "content_submission_enddate": "2021-06-06T18:29:59.000Z", "rewards": null, "target_collection_category": [ "Demo Practice Question Set" ], "content_types": [], "targetCollectionType": ["Question Set"], "targetprimarycategories": [ { "identifier": "obj-cat:practice-question-set_content_all", "name": "Practice Question Set", "targetObjectType": "Content" } ], }
For the “Search & Add” modal:
This will be enabled based on a
contentAdditionMode
property to be added to the configuration table, which will have an array of strings:search | add
This value will be read via an API call to the
configuration/v1/search
endpoint on loading this component with the selected primary category included in the request.If search is to be enabled for the selected primary category, the list of collections of the required target collection category to display in the search will be fetched by making the following API call:
POST
/composite/v1/search
(No change)Code Block language json { "request": { "filters": { "objectType": ["Collection"], "status":["Draft"], "subject": ["Mathematics"], "medium": ["English"], "gradeLevel": ["Class 4"], "primaryCategory":"Question Paper", "channel":"", "limit": 1000, "not_exists":["programId"] } } }
In case of editing an already created draft project, this tab opens up on load. In that case, the category definition of the selected target collection (or questionSet) as well as a list of already created objects of that collection/question set category are to be populated. Both may be done via the same process as above, where the only difference is that the selected target collection can be retrieved from
this.selectedTargetCollection
, and the target collection type may be retrieved fromthis.programDetails.targetCollectionType
Create New Project: Add New
Display the “Add New” button only if the
targetCollectionType === “Question Set”
for the draft programNavigate to the Question Set Editor on clicking the "Add New" button [6] (Google Slide)
Use the category definition of the selected target question set to modify the behaviour of the question set editor, using
maxDepth
.A data property
hideAddQuestion
may be added to the routing config, to disable the "Create New" button on the Question Set Editor in this caseCode Block language json { path: 'edit/:programId', component: CreateProgramComponent, canActivate: [ProgramsService, AuthGuard], pathMatch: 'full', data: { ... }, children: [ { path: 'questionSet', component: QuestionSetEditorComponent, pathMatch: 'full', data: { hideHeaderNFooter: 'true', hideAddQuestion: true, telemetry: { ... } } }
The
programId
will be added to the created questionSet under aprogramId
attributeOn "Save", redirect to the draft project creation screen with the created Question Set returned to the parent component and added to the
tempQuestionSets
array, to display in the selected list [8] (Google Slide)
Create New Project: Publish
On “Publish”, the existing workflow to publish the project will be followed with some modifications for projects with
targetCollectionType === ‘Question Set’
The question sets added to the program will be saved to the program
config
object inconfig.collections
The
contentAdditionMode
will also be saved in the programconfig
The identifiers will be saved in
collectionIds
POST
content/program/v1/update
Code Block language json { "request": { "name": "Test", "description": "1234", "nomination_enddate": null, "shortlisting_enddate": null, "content_submission_enddate": "2021-07-04T18:29:59.000Z", "rewards": null, "target_collection_category": ["Demo Practice Question Set"], "content_types": [], "targetprimarycategories": [{ "identifier": "obj-cat:exam-question_content_01309282781705830427", "name": "Exam Question", "targetObjectType": "Content" }], "sourcing_org_name": "NIT", "rootorg_id": "01309282781705830427", "createdby": "5a587cc1-e018-4859-a0a8-e842650b9d64", "createdon": "2021-06-12T07:39:30.060Z", "startdate": "2021-06-12T07:39:30.060Z", "slug": "sunbird", "type": "private", "default_roles": ["CONTRIBUTOR"], "enddate": "2021-08-08T18:29:59.000Z", "guidelines_url": null, "status": "Draft", "program_id": "b7237ab0-cb50-11eb-a18f-2b66ffec9e33", "collectionIds": [], "config": { ... "contentAdditionMode": "addnew", "collections": [ { "identifier": "", "children": [] } ]
POST
content/program/v1/publish
orPOST
content/program/v1/unlist/publish
(depending on whether nominations have been enabled or not)Code Block language json { "request": { "program_id": "3d5ddd30-bff0-11eb-8aa6-59968608366d", "channel":"sunbird" } }
Inside the Program Service, create new functions to handle publishing for programs with
contentAdditionMode === 'addnew'
Modify the
copyCollections
function as follows:Code Block if(_.get(data, 'config.contentAdditionMode') === 'add') { rspObj.contentAdditionMode = 'add'; rspObj.result = collections; cb(null, rsbObj); return true; }
Modify the
publishProgram
function as follows:Code Block language js function publishProgram(req, response) { var data = req.body; model.program.findByPk(data.request.program_id) .then(function (res) { const cb = function(errObj, rspObj) { if (!errObj && rspObj) { res.copiedCollections = []; if (rspObj && rspObj.result) { if(rspObj.contentAdditionMode === 'addnew') { res.copiedCollections = rspObj.result } res.copiedCollections = _.map(rspObj.result, (collection) => { return collection.result.content_id; }); } }
...