From 84e9636a82433720d636d2e4b9181cdc5f851dbb Mon Sep 17 00:00:00 2001
From: Reshma_Prasad <reshma.vadakkemuriyil@tarento.com>
Date: Mon, 17 Apr 2023 11:22:56 +0530
Subject: [PATCH] Commiting code for bulk upload of questions from excelsheet

---
 .../app/handlers/QuestionExcelParser.scala    | 91 +++++++++++++------
 .../app/utils/Constants.java                  | 13 +++
 2 files changed, 78 insertions(+), 26 deletions(-)
 create mode 100644 assessment-api/assessment-service/app/utils/Constants.java

diff --git a/assessment-api/assessment-service/app/handlers/QuestionExcelParser.scala b/assessment-api/assessment-service/app/handlers/QuestionExcelParser.scala
index f8f013a72..dbc920f73 100644
--- a/assessment-api/assessment-service/app/handlers/QuestionExcelParser.scala
+++ b/assessment-api/assessment-service/app/handlers/QuestionExcelParser.scala
@@ -1,38 +1,58 @@
 package handlers
 
 import org.apache.commons.lang3.StringUtils
+import org.apache.poi.ss.usermodel.CellType
 import org.apache.poi.xssf.usermodel.{XSSFRow, XSSFWorkbook}
+import org.slf4j.{Logger, LoggerFactory}
+import org.sunbird.cache.impl.RedisCache
+import utils.Constants
 
 import java.io.{File, FileInputStream}
 import java.util
 import scala.collection.JavaConverters._
-import org.slf4j.{Logger, LoggerFactory}
-import org.sunbird.cache.impl.RedisCache
 
 object QuestionExcelParser {
 
   private val logger: Logger = LoggerFactory.getLogger(RedisCache.getClass.getCanonicalName)
-  def getQuestions(file: File) = {
 
+  def getQuestions(fileName: String, file: File) = {
     try {
+      var board = "";
+      if (fileName.startsWith("GNM")) { // checks for the filename that starts with GNM or ANM
+        board = "GNM"
+      } else if (fileName.startsWith("ANM")) {
+        board = "ANM"
+      }
+      if (board.isEmpty) {
+        throw new RuntimeException("Invalid file name")
+      }
       val workbook = new XSSFWorkbook(new FileInputStream(file))
-      val sheet = workbook.getSheetAt(0)
-      logger.info("Inside the getQuestions")
-      (1 until sheet.getPhysicalNumberOfRows)
-        .filter(rowNum => {
-          val oRow = Option(sheet.getRow(rowNum))
-          oRow match {
-            case Some(x) => {
-              val questionText = sheet.getRow(rowNum).getCell(4)
-              val questionType = sheet.getRow(rowNum).getCell(7)
-              boolean2Boolean("MCQ".equals(questionType.toString))
+      val sheets = (2 until workbook.getNumberOfSheets).map(index => workbook.getSheetAt(index))  // iterates over the excelsheet
+      sheets.flatMap(sheet => {
+        logger.info("Inside the getQuestions")
+        (1 until sheet.getPhysicalNumberOfRows)  // iterates over each row in the sheet
+          .filter(rowNum => {
+            val oRow = Option(sheet.getRow(rowNum))
+            // matching the row value to determine the value of objects
+            oRow match {
+              case Some(x) => {
+                val questionType = sheet.getRow(rowNum).getCell(11)
+                val isMCQ = questionType.toString.startsWith(Constants.MCQ) || questionType.toString.endsWith(Constants.MCQ) // checks questionType is MCQ
+                val isMTF = Constants.MTF.equals(questionType.toString) || Constants.MATCH_THE_FOLLOWING.equals(questionType.toString)
+                val isFITB = Constants.FITB.equals(questionType.toString)
+                val answerCell = sheet.getRow(rowNum).getCell(9)
+                val isAnswerNotBlank = answerCell.getCellType() != CellType.BLANK
+                isMCQ || isMTF || isFITB && isAnswerNotBlank
+              }
+              case None => false
             }
-            case None => false
-          }
-        })
-        .map(rowNum => parseQuestion(sheet.getRow(rowNum))).toList
-    } catch {
-      case e : Exception => throw new Exception("Invalid File")
+          })
+          .map(rowNum => parseQuestion(sheet.getRow(rowNum), sheet.getSheetName, board)).toList
+      })
+    }
+
+    catch {
+      case e: Exception => throw new Exception("Invalid File")
     }
   }
 
@@ -59,40 +79,59 @@ object QuestionExcelParser {
     mapOption
   }
 
+  // determines whether the Opton is correct
   def isOptionAnswer(optSeq: String, answerText: String): Boolean = {
 
     val correctOpt = answerText.split(",").map(_.trim)
 
     correctOpt.contains(optSeq)
+
   }
 
-  def parseQuestion(xssFRow: XSSFRow) = {
+  def parseQuestion(xssFRow: XSSFRow, sheetName: String, board: String) = {
     val question = buildDefaultQuestion()
 
-
     val rowContent = (0 until xssFRow.getPhysicalNumberOfCells)
       .map(colId => Option(xssFRow.getCell(colId)).getOrElse("").toString).toList
 
-    val questionText = rowContent.apply(4)
-    val answer = rowContent.apply(6).trim
+    //fetches data from sheet
+    val medium = rowContent.apply(7)
+    val subject = rowContent.apply(0)
+    val difficultyLevel = rowContent.apply(5)
+    val questionText = rowContent.apply(8)
+    val answer = rowContent.apply(10).trim
 
 
     var i = -1
-    val options = new util.ArrayList[util.Map[String, AnyRef]](rowContent.apply(5).split("\n").filter(StringUtils.isNotBlank).map(o => {
-      val option = o.split("[//)]").toList
+    val options = new util.ArrayList[util.Map[String, AnyRef]](rowContent.apply(9).split("\n").filter(StringUtils.isNotBlank).map(o => {
+      //      val option = o.split("[//)]").toList
+      val option = o.split("[.).]").toList
       val optSeq = option.apply(0).trim
+
       val optText = option.apply(1).trim
       i += 1
       buildOptionMap(optText, i, isOptionAnswer(optSeq, answer))
     }).toList.asJava)
 
-    val editorState = new java.util.HashMap().asInstanceOf[java.util.Map[String, AnyRef]]
+    val editorState = new util.HashMap().asInstanceOf[util.Map[String, AnyRef]]
+    question.put("board", board)
+    setArrayValue(question, medium, "medium")
+    setArrayValue(question, subject, "subject")
+    setArrayValue(question, sheetName, "gradeLevel")
+    setArrayValue(question, difficultyLevel, "difficultyLevel")
     editorState.put("options", options)
     editorState.put("question", questionText)
     logger.info("Inside the parseQuestion")
     question.put("body", questionText)
     question.put("editorState", editorState)
+
     question
   }
 
+
+  private def setArrayValue(question: util.Map[String, AnyRef], medium: String, questionKey: String) = {
+    val valueList = new util.ArrayList[String]();
+    valueList.add(medium);
+    question.put(questionKey, valueList)
+  }
 }
diff --git a/assessment-api/assessment-service/app/utils/Constants.java b/assessment-api/assessment-service/app/utils/Constants.java
new file mode 100644
index 000000000..d4cad0f33
--- /dev/null
+++ b/assessment-api/assessment-service/app/utils/Constants.java
@@ -0,0 +1,13 @@
+package utils;
+
+
+public class Constants {
+
+    public static String MCQ ="MCQ";
+    public static String MATCH_THE_FOLLOWING = "Match the following" ;
+    public static String MTF = "MTF";
+    public static String FITB = "Fill in the blanks";
+
+    private Constants() {
+    }
+}
-- 
GitLab