Skip to content

Commit

Permalink
Merge pull request #823 from joffinjoy/question-copy-4.9.0-v2
Browse files Browse the repository at this point in the history
Issue #SB-29145 feat: Added Question & QuestionSet Copy APIs With BranchingLogic Copy.
  • Loading branch information
pallakartheekreddy authored May 16, 2022
2 parents 7673167 + e52aedc commit a74aae9
Show file tree
Hide file tree
Showing 16 changed files with 1,019 additions and 13 deletions.
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

0 comments on commit a74aae9

Please sign in to comment.