...
| Scenario | Write Request | Read Request(Condition) |
---|
1 | User consuming individual content. [New] | Code Block |
---|
| {
"userid": "<<userid>>",
"courseid": "<<contentid>>",
"batchid": "<<contentid>>",
"contentid": "<<contentid>>"
} |
| WHERE userid='<<userid>>' and courseid ='<<contentid>>' |
2 | User consuming a content with in a collection. [Existing] | Code Block |
---|
| {
"userid": "<<userid>>",
"courseid": "<<courseid>>",
"batchid": "<<batchid>>",
"contentid": "<<contentid>>"
} |
| WHERE userid='<<userid>>' and courseid ='<<courseid>>' and batchid ='<<batchid>>' and contentid='<<contentid>>' |
3 | User consuming a content with in a collection. [New] | Code Block |
---|
| {
"userid": "<<userid>>",
"courseid": "<<courseid>>",
"batchid": "<<batchid>>",
"contentid": "<<contentid>>"
} |
Note: When it is consumed with in this context. | WHERE userid='<<userid>>' and courseid ='<<contentid>>' OR WHERE userid='<<userid>>' and courseid ='<<courseid>>' and batchid ='<<batchid>>' and contentid='<<contentid>>' |
Extending Viewer-Service Design to support Program Context:
When a user enrols for program,once successfully capturing the data, an program context event will be generated
Enrolment Updater Job will read these events and use viewer-service read/write apis to update the corresponding content status based on the predefined rules set for a context
...
...
Scenario
...
Write Request
...
Read Request(Condition)
...
User consuming a content with in a collection by enrolling to program. [Existing]
...
Code Block |
---|
|
{
"userid": "<<userid>>",
"courseid": "<<courseid>>",
"batchid": "<<programid>>",
"contentid": "<<contentid>>"
} |
...
WHERE userid='<<userid>>' and courseid ='<<courseid>>' and batchid ='<<programid>>' and contentid='<<contentid>>'
...
User consuming a content with in a collection by enrolling to program . [New]
...
Code Block |
---|
|
{
"userid": "<<userid>>",
"courseid": "<<courseid>>",
"batchid": "<<programid>>",
"contentid": "<<contentid>>"
} |
...
WHERE userid='<<userid>>' and courseid ='<<contentid>>'
OR
WHERE userid='<<userid>>' and courseid ='<<courseid>>' and batchid ='<<programid>>' and contentid='<<contentid>>'
Program Metadata Table Schema:
...
Field
...
DataType
...
Description
...
identifier
...
String
...
Unique id for program
...
name
...
String
...
Name of the program
...
children
...
List[String]
...
list of collections in the program
Ex: [collection1,collection2]
Content View Lifecycle:
When the user view the content in context of a collection and batch, for the first time its start, progress update and end triggers are processed. Revisit (2nd - nth view) of the content will be ignored to process and update the DB.
...
If, collectionId and batchId are part of the request, then, individual content progress and overall collection progress is captured and computed.
...
...
With normal collection types, the map values gets distributed to multiple sstables with append, which might lead to read latency issues
To the handle the scenario, will consider the frozen collection types, which will helpful in avoiding tombstone and multiple sstable reads
...
...
Current vs New (Viewer-Service) APIs:
We need to continue supporting the current APIs (v1) before deprecate and delete. So, it requires to work with both the APIs with backward compatibility.
Enhance
...
Current APIs to read summary from aggregate table.
Enhance the below APIs to read the progress and score metrics from user_activity_agg
table.
...
Expand |
---|
title | POST - /v1/view/start |
---|
|
Request: Code Block |
---|
| {
"request": {
"userId": "{{userId}}",
"collectionId" : "{{collectionId}}",
"batchId": "{{batchId}}",
"contentId": "{{contentId}}"
}
} |
Response: Code Block |
---|
| {
"id": "api.view.start",
"ver": "v2v1",
"ts": "2021-06-23 05:37:40:575+0000",
"params": {
"resmsgid": null,
"msgid": "5e763bc2-b072-440d-916e-da787881b1b9",
"err": null,
"status": "success",
"errmsg": null
},
"responseCode": "OK",
"result": {
"{{contentId}}": "Progress started"
}
}
|
|
...
Expand |
---|
title | POST - /v1/view/update |
---|
|
Request: Code Block |
---|
| {
"request": {
"userId": "{{userId}}",
"collectionId" : "{{collectionId}}",
"batchId": "{{batchId}}",
"contentId": "{{contentId}}",
"progress": 34
}
} |
Response: Code Block |
---|
| 200 OK:
{
"id": "api.view.update",
"ver": "v2v1",
"ts": "2021-06-23 05:37:40:575+0000",
"params": {
"resmsgid": null,
"msgid": "5e763bc2-b072-440d-916e-da787881b1b9",
"err": null,
"status": "success",
"errmsg": null
},
"responseCode": "OK",
"result": {
"{{contentId}}": "SUCCESS"
}
}
4XX or 5XX Error:
{
"id": "api.view.update",
"ver": "v2v1",
"ts": "2021-06-23 05:37:40:575+0000",
"params": {
"resmsgid": null,
"msgid": "5e763bc2-b072-440d-916e-da787881b1b9",
"err": ERR_Error_Code,
"status": "failed",
"errmsg": ERR_error_msg
},
"responseCode": "BAD_REQUEST"/"SERVER_ERROR",
"result": {
}
} |
|
...
Expand |
---|
title | POST - /v1/assessment/submit |
---|
|
Request: Code Block |
---|
| {
"request": {
"userId": "{{userId}}",
"collectionId" : "{{collectionId}}",
"batchId": "{{batchId}}",
"contentId": "{{contentId}}",
"assessments": [{
{{assess_event}} //Mandatory for self-assess contents
}]
}
} |
Response: Code Block |
---|
{
"id": "api.view.assess",
"ver": "v2v1",
"ts": "2021-06-23 05:37:40:575+0000",
"params": {
"resmsgid": null,
"msgid": "5e763bc2-b072-440d-916e-da787881b1b9",
"err": null,
"status": "success",
"errmsg": null
},
"responseCode": "OK",
"result": {
"{{contentId}}": "SUCCESS"
}
} |
|
...
Expand |
---|
|
Request: Code Block |
---|
| {
"request": {
"userId": "{{userId}}",
"collectionId" : "{{collectionId}}",
"batchId": "{{batchId}}",
"contentId": "{{contentId}}"
}
} |
Response: Code Block |
---|
| {
"id": "api.view.end",
"ver": "v2v1",
"ts": "2021-06-23 05:37:40:575+0000",
"params": {
"resmsgid": null,
"msgid": "5e763bc2-b072-440d-916e-da787881b1b9",
"err": null,
"status": "success",
"errmsg": null
},
"responseCode": "OK",
"result": {
"{{contentId}}": "Progress ended"
}
}
|
|
...
Expand |
---|
title | POST - /v1/view/read |
---|
|
Request: Code Block |
---|
| {
"request": {
"userId": "{{userId}}",
"contentId": ["do_123", "do_1234"],
"collectionId" : "{{collectionId}}", //optional
"batchId": "{{batchId}}" // optional
}
} |
Response: Code Block |
---|
| {
"id": "api.view.read",
"ver": "v2v1",
"ts": "2021-06-23 05:37:40:575+0000",
"params": {
"resmsgid": null,
"msgid": "5e763bc2-b072-440d-916e-da787881b1b9",
"err": null,
"status": "success",
"errmsg": null
},
"responseCode": "OK",
"result": {
"userId": "{{userId}}",
"collectionId": "{{collectionId}}",
"batchId": "{{batchId}}",
"contents": [{
"identifier": "{contentId}",
"progress": 45,
"score": {{best_score}},
"max_score": {{max_score}}
}]
}
}
|
|
...
Expand |
---|
title | GET - /v1/summary/list/:userId |
---|
|
Response: Code Block |
---|
| {
"id": "api.summary.list",
"ver": "v2v1",
"ts": "2021-06-23 05:59:54:984+0000",
"params": {
"resmsgid": null,
"msgid": "95e4942d-cbe8-477d-aebd-ad8e6de4bfc8",
"err": null,
"status": "success",
"errmsg": null
},
"responseCode": "OK",
"result": {
"summary": [
{
"userId": "{{userId}}",
"collectionId": "{{collectionId}}",
"batchId": "{{batchId}}",
"enrolledDate": 1624275377301,
"active": true,
"contentStatus": {
"{{contentId}}": {{status}}
},
"assessmentStatus": {
"assessmentId": {
"score": {{best_score}},
"max_score": {{max_score}}
}
},
"collection": {
"identifier": "{{collectionId}}",
"name": "{{collectionName}}",
"logo": "{{logo Url}}",
"leafNodesCount": {{leafNodeCount}},
"description": "{{description}}"
},
"issuedCertificates": [{
"name": "{{certName}}",
"id": "certificateId",
"token": "{{certToken}}",
"lastIssuedOn": "{{lastIssuedOn}}"
}],
"completedOn": {{completion_date}},
"progress": {{progress}},
"status": {{status}}
}
]
}
}
|
|
...
Expand |
---|
title | POST - /v1/summary/read |
---|
|
Request: Code Block |
---|
{
"request": {
"userId": "{{userId}}",
"collectionId" : "{{collectionId}}",
"batchId": "{{batchId}}"
}
} |
Response: Code Block |
---|
| {
"id": "api.summary.read",
"ver": "v2v1",
"ts": "2021-06-23 05:59:54:984+0000",
"params": {
"resmsgid": null,
"msgid": "95e4942d-cbe8-477d-aebd-ad8e6de4bfc8",
"err": null,
"status": "success",
"errmsg": null
},
"responseCode": "OK",
"result": {
"userId": "{{userId}}",
"collectionId": "{{collectionId}}",
"batchId": "{{batchId}}",
"enrolledDate": 1624275377301,
"active": true,
"contentStatus": {
"{{contentId}}": {{status}}
},
"assessmentStatus": {
"assessmentId": {
"score": {{best_score}},
"max_score": {{max_score}}
}
},
"collection": {
"identifier": "{{collectionId}}",
"name": "{{collectionName}}",
"logo": "{{logo Url}}",
"leafNodesCount": {{leafNodeCount}},
"description": "{{description}}"
},
"issuedCertificates": [{
"name": "{{certName}}",
"id": "certificateId",
"token": "{{certToken}}",
"lastIssuedOn": "{{lastIssuedOn}}"
}],
"completedOn": {{completion_date}},
"progress": {{progress}},
"status": {{status}}
}
}
|
|
...
Expand |
---|
title | DELETE - /v1/summary/delete/:userId?all - To Delete all enrolments |
---|
|
Response: Code Block |
---|
| Response:
{
"id": "api.summary.delete",
"ver": "v2v1",
"ts": "2021-06-23 05:37:40:575+0000",
"params": {
"resmsgid": null,
"msgid": "5e763bc2-b072-440d-916e-da787881b1b9",
"err": null,
"status": "success",
"errmsg": null
},
"responseCode": "OK",
"result": {}
}
|
|
Expand |
---|
title | DELETE - /v1/summary/delete/:userId - To Delete specific enrolments |
---|
|
Request: Code Block |
---|
{
"request": {
"userId": "{{userId}}",
"collectionId" : "{{collectionId}}",
"batchId": "{{batchId}}"
}
} |
Response: Code Block |
---|
| Response:
{
"id": "api.summary.delete",
"ver": "v2v1",
"ts": "2021-06-23 05:37:40:575+0000",
"params": {
"resmsgid": null,
"msgid": "5e763bc2-b072-440d-916e-da787881b1b9",
"err": null,
"status": "success",
"errmsg": null
},
"responseCode": "OK",
"result": {}
}
|
|
...
Expand |
---|
title | GET - /v1/summary/download/:userId?format=csv |
---|
|
Response: Code Block |
---|
{
"id": "api.summary.download",
"ver": "v2v1",
"ts": "2021-06-23 05:37:40:575+0000",
"params": {
"resmsgid": null,
"msgid": "5e763bc2-b072-440d-916e-da787881b1b9",
"err": null,
"status": "success",
"errmsg": null
},
"responseCode": "OK",
"result": {
"url": "{{userId}}_viewer_summary.csv"
}
} |
|
Expand |
---|
title | GET - /v1/summary/download/:userId |
---|
|
Response: Code Block |
---|
{
"id": "api.summary.download",
"ver": "v2v1",
"ts": "2021-06-23 05:37:40:575+0000",
"params": {
"resmsgid": null,
"msgid": "5e763bc2-b072-440d-916e-da787881b1b9",
"err": null,
"status": "success",
"errmsg": null
},
"responseCode": "OK",
"result": {
"url": "{{userId}}_viewer_summary.json"
}
} |
|
...