Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #SB-29145 feat: Added Question & QuestionSet Copy APIs With BranchingLogic Copy. #823

Merged
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.sunbird.common.{DateUtils, Platform}
import org.sunbird.graph.OntologyEngineContext
import org.sunbird.graph.nodes.DataNode
import org.sunbird.graph.utils.NodeUtil
import org.sunbird.managers.AssessmentManager
import org.sunbird.managers.{AssessmentManager, CopyManager}
import org.sunbird.utils.RequestUtil

import java.util
Expand Down Expand Up @@ -36,6 +36,7 @@ class QuestionActor @Inject()(implicit oec: OntologyEngineContext) extends BaseA
case "systemUpdateQuestion" => systemUpdate(request)
case "listQuestions" => listQuestions(request)
case "rejectQuestion" => reject(request)
case "copyQuestion" => copy(request)
case _ => ERROR(request.getOperation)
}

Expand Down Expand Up @@ -128,4 +129,9 @@ class QuestionActor @Inject()(implicit oec: OntologyEngineContext) extends BaseA
AssessmentManager.updateNode(updateRequest)
})
}

def copy(request: Request): Future[Response] ={
RequestUtil.restrictProperties(request)
CopyManager.copy(request)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.sunbird.actors

import java.util

import javax.inject.Inject
import org.apache.commons.collections4.CollectionUtils
import org.sunbird.`object`.importer.{ImportConfig, ImportManager}
Expand All @@ -13,7 +12,7 @@ import org.sunbird.graph.OntologyEngineContext
import org.sunbird.graph.nodes.DataNode
import org.sunbird.graph.dac.model.Node
import org.sunbird.managers.HierarchyManager.hierarchyPrefix
import org.sunbird.managers.{AssessmentManager, HierarchyManager, UpdateHierarchyManager}
import org.sunbird.managers.{AssessmentManager, CopyManager, HierarchyManager, UpdateHierarchyManager}
import org.sunbird.utils.RequestUtil

import scala.collection.JavaConverters._
Expand All @@ -40,6 +39,7 @@ class QuestionSetActor @Inject()(implicit oec: OntologyEngineContext) extends Ba
case "rejectQuestionSet" => reject(request)
case "importQuestionSet" => importQuestionSet(request)
case "systemUpdateQuestionSet" => systemUpdate(request)
case "copyQuestionSet" => copy(request)
case _ => ERROR(request.getOperation)
}

Expand Down Expand Up @@ -157,4 +157,8 @@ class QuestionSetActor @Inject()(implicit oec: OntologyEngineContext) extends Ba
}).map(node => ResponseHandler.OK.put("identifier", identifier).put("status", "success"))
}

def copy(request: Request): Future[Response] ={
RequestUtil.restrictProperties(request)
CopyManager.copy(request)
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.sunbird.utils

object AssessmentConstants {
val REQUIRED_KEYS: List[String] = List("createdBy", "createdFor")
val ERR_INVALID_REQUEST: String = "ERR_INVALID_REQUEST"
val ERR_INVALID_OBJECT_TYPE: String = "ERR_INVALID_OBJECT_TYPE"
val COPY_SCHEME: String = "copyScheme"
val MIME_TYPE: String = "mimeType"
val QUESTIONSET_MIME_TYPE: String = "application/vnd.sunbird.questionset"
val STATUS: String = "status"
val COPY_TYPE: String = "copyType"
val SCHEMA_NAME: String = "schemaName"
val VERSION: String = "version"
val ROOT_ID: String = "rootId"
val MODE: String = "mode"
val COPY_TYPE_SHALLOW: String = "shallow"
val QUESTIONSET_SCHEMA_NAME: String = "questionset"
val SCHEMA_VERSION: String = "1.0"
val IDENTIFIER: String = "identifier"
val QUESTION: String = "question"
val HIERARCHY: String = "hierarchy"
val CHILDREN: String = "children"
val ORIGIN: String = "origin"
val ORIGIN_DATA: String = "originData"
val CONTENT_TYPE: String = "contentType"
val ROOT: String = "root"
val NODES_MODIFIED: String = "nodesModified"
val VISIBILITY: String = "visibility"
val METADATA: String = "metadata"
val VERSION_KEY: String = "versionKey"
val PRIMARY_CATEGORY : String = "primaryCategory"
val QUESTIONSET : String = "questionSet"
val OBJECT_TYPE : String = "objectType"
val COPY_TYPE_DEEP: String = "deep"
val QUESTION_MIME_TYPE: String = "application/vnd.sunbird.question"
val QUESTION_SCHEMA_NAME: String = "question"
val VISIBILITY_PARENT: String = "Parent"
val VISIBILITY_DEFAULT: String = "Default"
val BRANCHING_LOGIC: String = "branchingLogic"
val COPY_OF: String = "copyOf"
val CONTAINS_BL: String = "containsBL"
val IDENTIFIERS: String = "identifiers"
val IS_NEW: String = "isNew"
val TARGET: String = "target"
val PRE_CONDITION: String = "preCondition"
val SOURCE: String = "source"
val PRE_CONDITION_VAR : String = "var"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package org.sunbird.utils

import org.apache.commons.lang.StringUtils
import org.sunbird.common.dto.Request

import java.util
import scala.collection.JavaConverters._
import scala.collection.JavaConversions.{asScalaBuffer}

object BranchingUtil {

def generateBranchingRecord(nodesModified: util.HashMap[String, AnyRef]): util.HashMap[String, AnyRef] = {
val idSet = nodesModified.keySet().asScala.toList
val branchingRecord = new util.HashMap[String, AnyRef]()
idSet.map(id => {
val nodeMetaData = nodesModified.getOrDefault(id, new util.HashMap()).asInstanceOf[util.Map[String, AnyRef]].getOrDefault(AssessmentConstants.METADATA, new util.HashMap()).asInstanceOf[util.Map[String, AnyRef]]
val containsBL = nodeMetaData.containsKey(AssessmentConstants.BRANCHING_LOGIC)
branchingRecord.put(id, new util.HashMap[String, AnyRef]() {
{
if (containsBL) {
put(AssessmentConstants.BRANCHING_LOGIC, nodeMetaData.get(AssessmentConstants.BRANCHING_LOGIC))
nodeMetaData.remove(AssessmentConstants.BRANCHING_LOGIC)
}
put(AssessmentConstants.CONTAINS_BL, containsBL.asInstanceOf[AnyRef])
put(AssessmentConstants.COPY_OF, nodeMetaData.get(AssessmentConstants.COPY_OF).asInstanceOf[String])
}
})
nodeMetaData.remove(AssessmentConstants.COPY_OF)
})
branchingRecord
}

def hierarchyRequestModifier(request: Request, branchingRecord: util.HashMap[String, AnyRef], identifiers: util.Map[String, String]) = {
val nodesModified: java.util.HashMap[String, AnyRef] = request.getRequest.get(HierarchyConstants.NODES_MODIFIED).asInstanceOf[java.util.HashMap[String, AnyRef]]
val hierarchy: java.util.HashMap[String, AnyRef] = request.getRequest.get(HierarchyConstants.HIERARCHY).asInstanceOf[java.util.HashMap[String, AnyRef]]
val oldToNewIdMap = getIdentifierMapping(branchingRecord, identifiers)
branchingRecord.keySet().asScala.toList.map(id => {
val nodeInfo = branchingRecord.get(id).asInstanceOf[util.HashMap[String, AnyRef]]
val node = nodesModified.get(id).asInstanceOf[util.HashMap[String, AnyRef]]
val nodeMetaData = node.get(AssessmentConstants.METADATA).asInstanceOf[util.HashMap[String, AnyRef]]
val newId = identifiers.get(id)
if (nodeInfo.get(AssessmentConstants.CONTAINS_BL).asInstanceOf[Boolean]) {
val branchingLogic = nodeInfo.get(AssessmentConstants.BRANCHING_LOGIC).asInstanceOf[util.HashMap[String, AnyRef]]
branchingLogicModifier(branchingLogic, oldToNewIdMap)
nodeMetaData.put(AssessmentConstants.BRANCHING_LOGIC, branchingLogic)
}
node.put(AssessmentConstants.IS_NEW, false.asInstanceOf[AnyRef])
nodesModified.remove(id)
nodesModified.put(newId, node)
})
hierarchy.keySet().asScala.toList.map(id => {
val nodeHierarchy = hierarchy.get(id).asInstanceOf[util.HashMap[String, AnyRef]]
val children = nodeHierarchy.get(AssessmentConstants.CHILDREN).asInstanceOf[util.ArrayList[String]]
val newChildrenList = new util.ArrayList[String]
children.map(identifier => {
if (identifiers.containsKey(identifier)) newChildrenList.add(identifiers.get(identifier)) else newChildrenList.add(identifier)
})
nodeHierarchy.put(AssessmentConstants.CHILDREN, newChildrenList)
if (identifiers.containsKey(id)) {
hierarchy.remove(id)
hierarchy.put(identifiers.get(id), nodeHierarchy)
}
})
request
}

def branchingLogicModifier(branchingLogic: util.HashMap[String, AnyRef], oldToNewIdMap: util.Map[String, String]): Unit = {
branchingLogic.keySet().asScala.toList.map(identifier => {
val nodeBL = branchingLogic.get(identifier).asInstanceOf[util.HashMap[String, AnyRef]]
nodeBL.keySet().asScala.toList.map(key => {
if (StringUtils.equalsIgnoreCase(key, AssessmentConstants.TARGET)) branchingLogicArrayHandler(nodeBL, AssessmentConstants.TARGET, oldToNewIdMap)
else if (StringUtils.equalsIgnoreCase(key, AssessmentConstants.PRE_CONDITION)) preConditionHandler(nodeBL, oldToNewIdMap)
else if (StringUtils.equalsIgnoreCase(key, AssessmentConstants.SOURCE)) branchingLogicArrayHandler(nodeBL, AssessmentConstants.SOURCE, oldToNewIdMap)
})
if (oldToNewIdMap.containsKey(identifier)) {
branchingLogic.put(oldToNewIdMap.get(identifier), nodeBL)
branchingLogic.remove(identifier)
}
})
}

def getIdentifierMapping(branchingRecord: util.HashMap[String, AnyRef], identifiers: util.Map[String, String]): util.Map[String, String] = {
val oldToNewIdMap = new util.HashMap[String, String]()
branchingRecord.keySet().asScala.toList.map(id => {
val nodeInfo = branchingRecord.get(id).asInstanceOf[util.HashMap[String, AnyRef]]
val newId = identifiers.get(id)
val oldId = nodeInfo.get(AssessmentConstants.COPY_OF).asInstanceOf[String]
oldToNewIdMap.put(oldId, newId)
})
oldToNewIdMap
}

def branchingLogicArrayHandler(nodeBL: util.HashMap[String, AnyRef], name: String, oldToNewIdMap: util.Map[String, String]) = {
val branchingLogicArray = nodeBL.getOrDefault(name, new util.ArrayList[String]).asInstanceOf[util.ArrayList[String]]
val newBranchingLogicArray = new util.ArrayList[String]()
branchingLogicArray.map(id => {
if (oldToNewIdMap.containsKey(id)) {
newBranchingLogicArray.add(oldToNewIdMap.get(id))
} else newBranchingLogicArray.add(id)
})
nodeBL.put(name, newBranchingLogicArray)
}

def preConditionHandler(nodeBL: util.HashMap[String, AnyRef], oldToNewIdMap: util.Map[String, String]): Unit = {
val preCondition = nodeBL.get(AssessmentConstants.PRE_CONDITION).asInstanceOf[util.HashMap[String, AnyRef]]
preCondition.keySet().asScala.toList.map(key => {
val conjunctionArray = preCondition.get(key).asInstanceOf[util.ArrayList[String]]
val condition = conjunctionArray.get(0).asInstanceOf[util.HashMap[String, AnyRef]]
condition.keySet().asScala.toList.map(logicOp => {
val conditionArray = condition.get(logicOp).asInstanceOf[util.ArrayList[String]]
val sourceQuestionRecord = conditionArray.get(0).asInstanceOf[util.HashMap[String, AnyRef]]
val preConditionVar = sourceQuestionRecord.get(AssessmentConstants.PRE_CONDITION_VAR).asInstanceOf[String]
val stringArray = preConditionVar.split("\\.")
if (oldToNewIdMap.containsKey(stringArray(0))) {
val newString = oldToNewIdMap.get(stringArray(0)) + "." + stringArray.drop(1).mkString(".")
sourceQuestionRecord.put(AssessmentConstants.PRE_CONDITION_VAR, newString)
}
})
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -412,5 +412,15 @@ import {
}
}

assessment.copy.origin_data=["name", "author", "license", "organisation"]
assessment.copy.props_to_remove=["downloadUrl", "artifactUrl", "variants",
"createdOn", "collections", "children", "lastUpdatedOn", "SYS_INTERNAL_LAST_UPDATED_ON",
"versionKey", "s3Key", "status", "pkgVersion", "toc_url", "mimeTypesCount",
"contentTypesCount", "leafNodesCount", "childNodes", "prevState", "lastPublishedOn",
"flagReasons", "compatibilityLevel", "size", "publishChecklist", "publishComment",
"LastPublishedBy", "rejectReasons", "rejectComment", "gradeLevel", "subject",
"medium", "board", "topic", "purpose", "subtopic", "contentCredits",
"owner", "collaborators", "creators", "contributors", "badgeAssertions", "dialcodes",
"concepts", "keywords", "reservedDialcodes", "dialcodeRequired", "leafNodes", "sYS_INTERNAL_LAST_UPDATED_ON", "prevStatus", "lastPublishedBy", "streamingUrl"]


Loading