From ca657fb26f1fa046efb5b7b208b55479bd09861c Mon Sep 17 00:00:00 2001 From: Jayaprakash8887 <jayaprakash.narayanaswamy@tarento.com> Date: Mon, 12 Jul 2021 18:55:38 +0530 Subject: [PATCH] Issue #SB-22862 feat: Collection CSV Hierarchy feature API - issue fixes --- .../manager/CollectionCSVManager.scala | 7 +++- .../manager/CollectionInputFileReader.scala | 4 +- .../validator/CollectionCSVValidator.scala | 42 +++++++++---------- 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/manager/CollectionCSVManager.scala b/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/manager/CollectionCSVManager.scala index 035147d3a..7ac96c54c 100644 --- a/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/manager/CollectionCSVManager.scala +++ b/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/manager/CollectionCSVManager.scala @@ -38,7 +38,7 @@ object CollectionCSVManager extends CollectionInputFileReader { // Validate if the mode is CREATE and children already exist in collection val children = collectionHierarchy(CollectionTOCConstants.CHILDREN).asInstanceOf[List[AnyRef]] if (mode.equals(CollectionTOCConstants.CREATE) && children.nonEmpty) - throw new ClientException("COLLECTION_CHILDREN_EXISTS", "Collection is already having children.") + throw new ClientException("COLLECTION_CHILDREN_EXISTS", "The “Folder Identifier†column is missing. Please correct and upload again.") //Validate the data format of the input CSV records validateRecordsDataFormat(inputFileExtension, csvRecords, mode) @@ -311,6 +311,7 @@ object CollectionCSVManager extends CollectionInputFileReader { } private def getNodesMetadata(folderInfoMap: mutable.LinkedHashMap[String, AnyRef], mode: String, frameworkID: String, collectionType: String): String = { + try { val collectionUnitType = contentTypeToUnitTypeMapping(collectionType) folderInfoMap.map(record => { val nodeInfo = record._2.asInstanceOf[scala.collection.mutable.Map[String, AnyRef]] @@ -329,6 +330,10 @@ object CollectionCSVManager extends CollectionInputFileReader { |"topic": ${if(nodeInfo.contains(CollectionTOCConstants.TOPIC) && nodeInfo(CollectionTOCConstants.TOPIC).asInstanceOf[List[String]].nonEmpty) nodeInfo(CollectionTOCConstants.TOPIC).asInstanceOf[List[String]].mkString("[\"","\",\"","\"]") else "[]"} }}""".stripMargin }).mkString(",") + } catch { + case _:Exception => throw new ClientException("CORRUPT_FOLDER_HIERARCHY", "Please verify the updated folder levels. Please ensure no new folder levels are added in the csv and upload again.") + } + } private def getHierarchyMetadata(folderInfoMap: mutable.LinkedHashMap[String, AnyRef], mode: String, linkedContentsDetails: List[Map[String, AnyRef]], collectionID: String, collectionName: String, collectionType: String): String = { diff --git a/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/manager/CollectionInputFileReader.scala b/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/manager/CollectionInputFileReader.scala index 890fcd6a4..68344d508 100644 --- a/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/manager/CollectionInputFileReader.scala +++ b/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/manager/CollectionInputFileReader.scala @@ -23,14 +23,12 @@ trait CollectionInputFileReader { private val CONTENT_FOLDER = "cloud_storage.content.folder" def readInputFile(request: Request): (String, util.List[CSVRecord], String) = { - println("CollectionInputFileReader --> readInputFile") - println("CollectionInputFileReader --> readInputFile --> fileUrl: " + request.getRequest.getOrDefault("fileUrl","").asInstanceOf[String]) val file = if(request.getRequest.getOrDefault("fileUrl","").asInstanceOf[String].nonEmpty){ val copiedFile = copyURLToFile(request.get(CollectionTOCConstants.IDENTIFIER).asInstanceOf[String], request.getRequest.getOrDefault("fileUrl", "").asInstanceOf[String]) request.getRequest.put("file",copiedFile) copiedFile } else request.getRequest.get("file").asInstanceOf[File] - println("CollectionInputFileReader --> readInputFile --> file.getAbsolutePath: " + file.getAbsolutePath) + val extension = "."+file.getAbsolutePath.split("\\.").last.toLowerCase extension match { diff --git a/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/validator/CollectionCSVValidator.scala b/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/validator/CollectionCSVValidator.scala index cbcbc64e3..27a890bb9 100644 --- a/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/validator/CollectionCSVValidator.scala +++ b/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/validator/CollectionCSVValidator.scala @@ -58,7 +58,7 @@ object CollectionCSVValidator { val csvRecords = csvFileParser.getRecords //Check if CSV Headers are empty - if (null == csvHeaders || csvHeaders.isEmpty) throw new ClientException("BLANK_CSV_DATA", "Did not find any Table of Contents data. Please check and upload again.") + if (null == csvHeaders || csvHeaders.isEmpty) throw new ClientException("BLANK_CSV_DATA", "Not data found in the file. Please correct and upload again.") //Check if the input CSV is 'CREATE' TOC file format or 'UPDATE' TOC file format val mode = if (csvHeaders.containsKey(collectionNodeIdentifierHeader.head)) CollectionTOCConstants.UPDATE else CollectionTOCConstants.CREATE @@ -94,9 +94,9 @@ object CollectionCSVValidator { def validateCSVRecordsDataFormat(csvRecords: util.List[CSVRecord], mode: String) { //Check if CSV Records are empty - if (null == csvRecords || csvRecords.isEmpty) throw new ClientException("BLANK_CSV_DATA", "Did not find any Table of Contents data. Please check and upload again.") + if (null == csvRecords || csvRecords.isEmpty) throw new ClientException("BLANK_CSV_DATA", "Not data found in the file. Please correct and upload again.") // check if records are more than allowed csv rows - if (csvRecords.nonEmpty && csvRecords.size > allowedNumberOfRecord) throw new ClientException("CSV_ROWS_EXCEEDS", "Number of rows in csv file is more than " + allowedNumberOfRecord) + if (csvRecords.nonEmpty && csvRecords.size > allowedNumberOfRecord) throw new ClientException("CSV_ROWS_EXCEEDS", s"Number of rows in the file exceeds the limit $allowedNumberOfRecord. Please reduce the number of folders and upload again.") validateMandatoryHeaderCols(csvRecords, mode) validateDuplicateRows(csvRecords) @@ -122,18 +122,18 @@ object CollectionCSVValidator { // validate Header sequence if((configHeaders.keySet diff csvHeader.keySet).isEmpty && (csvHeader.keySet diff configHeaders.keySet).isEmpty && csvHeader.toSeq != configHeaders.toSeq) { val colSeqString = ListMap(configHeaders.toSeq.sortBy(_._2):_*).keySet mkString "," - val errorMessage = MessageFormat.format("Found invalid sequence of columns. Please follow the order: "+colSeqString) + val errorMessage = MessageFormat.format("The columns in csv are not in correct order as required. Please check the sample file and follow the same order. ") throw new ClientException("INVALID_HEADER_SEQUENCE", errorMessage) } //Check if Some columns are missing if((configHeaders.toSet diff csvHeader.toSet).toMap.keySet.nonEmpty && (configHeaders.toSet diff csvHeader.toSet).toMap.keySet.toList.head.nonEmpty) { val missingCols = (configHeaders.toSet diff csvHeader.toSet).toMap.keySet mkString "," - throw new ClientException("REQUIRED_HEADER_MISSING", MessageFormat.format("Following columns are not found in the file: "+missingCols)) + throw new ClientException("REQUIRED_HEADER_MISSING", MessageFormat.format("Following columns are missing in the file. Please correct the same and upload again. \n "+missingCols)) } //Check if any additional columns found if((csvHeader.toSet diff configHeaders.toSet).toMap.keySet.nonEmpty && (csvHeader.toSet diff configHeaders.toSet).toMap.keySet.toList.head.nonEmpty) { val additionalCols = (csvHeader.toSet diff configHeaders.toSet).toMap.keySet mkString "," - throw new ClientException("ADDITIONAL_HEADER_FOUND", MessageFormat.format("Following additional columns are found in the file: "+additionalCols)) + throw new ClientException("ADDITIONAL_HEADER_FOUND", MessageFormat.format("Following invalid columns found in the file. Please check the sample file and provide correct columns. \n"+additionalCols)) } } @@ -176,7 +176,7 @@ object CollectionCSVValidator { } if(missingDataErrorMessage.trim.nonEmpty) - throw new ClientException("REQUIRED_FIELD_MISSING", "Following Rows have missing values: " + throw new ClientException("REQUIRED_FIELD_MISSING", "Following rows have missing folder values. Please correct and upload again: \n" + missingDataErrorMessage.split(",").distinct.mkString(CollectionTOCConstants.COMMA_SEPARATOR)) // Add column data validation messages from mandatory columns and hierarchy folder - END } @@ -200,7 +200,7 @@ object CollectionCSVValidator { }).mkString(CollectionTOCConstants.COMMA_SEPARATOR) if(dupRecordsList.trim.nonEmpty) - throw new ClientException("DUPLICATE_ROWS", "Following Rows are duplicate: " + dupRecordsList) + throw new ClientException("DUPLICATE_ROWS", "Following rows are duplicate, they have exactly same folder level values. Please correct and upload again: " + dupRecordsList) // Verify if there are any duplicate hierarchy folder structure - END } @@ -216,7 +216,7 @@ object CollectionCSVValidator { }).filter(msg => msg.nonEmpty).mkString(CollectionTOCConstants.COMMA_SEPARATOR) if(qrDataErrorMessage.trim.nonEmpty) - throw new ClientException("ERROR_QR_CODE_ENTRY", "Following rows have issues for QR Code entries: " + qrDataErrorMessage) + throw new ClientException("ERROR_QR_CODE_ENTRY", "Following rows have incorrect QR Code entries. “QR Code Required?†should be “Yes†if there is a value in QR Code column. Please correct and upload again: " + qrDataErrorMessage) // Verify if there are any QR Codes data entry issues - END // Verify if there are any duplicate QR Codes - START val dupQRListMsg = csvRecords.filter(csvRecord => { @@ -225,11 +225,11 @@ object CollectionCSVValidator { !csvRecord.getRecordNumber.equals(record.getRecordNumber) }) }).map(dupQRRecord => { - MessageFormat.format("\nRow {0} - {1}", (dupQRRecord.getRecordNumber+1).toString, dupQRRecord.get(CollectionTOCConstants.QR_CODE)) + MessageFormat.format("\nRow {0}", (dupQRRecord.getRecordNumber+1).toString) }).mkString(CollectionTOCConstants.COMMA_SEPARATOR) if(dupQRListMsg.trim.nonEmpty) - throw new ClientException("DUPLICATE_QR_CODE_ENTRY", "Following rows have duplicate QR Code entries: " + dupQRListMsg) + throw new ClientException("DUPLICATE_QR_CODE_ENTRY", "Following rows have duplicate QR Code values. Please correct and upload again: " + dupQRListMsg) // Verify if there are any duplicate QR Codes - END } @@ -249,7 +249,7 @@ object CollectionCSVValidator { }).filter(msg => msg.nonEmpty).mkString(CollectionTOCConstants.COMMA_SEPARATOR) if(missingLinkedContentDataList.trim.nonEmpty) - throw new ClientException("LINKED_CONTENTS_DATA_MISSING", "Following rows have linked contents data missing: " + missingLinkedContentDataList) + throw new ClientException("LINKED_CONTENTS_DATA_MISSING", "Following rows have missing “Linked Content†values. Please correct and upload again: " + missingLinkedContentDataList) // Check if data exists in Linked content columns - END } @@ -264,7 +264,7 @@ object CollectionCSVValidator { }).filter(msg => msg.nonEmpty).mkString(CollectionTOCConstants.COMMA_SEPARATOR) if (invalidCollectionNameErrorMessage.trim.nonEmpty) - throw new ClientException("CSV_INVALID_COLLECTION_NAME", "Following rows have invalid Collection Name: " + invalidCollectionNameErrorMessage) + throw new ClientException("CSV_INVALID_COLLECTION_NAME", "Following rows have invalid “Collection Nameâ€. Please correct and upload again: " + invalidCollectionNameErrorMessage) // validate collection name column in CSV - END TelemetryManager.log("CollectionCSVActor --> validateCSVRecordsDataAuthenticity --> after validating collection name column in CSV") } @@ -283,7 +283,7 @@ object CollectionCSVValidator { })}).filter(msg => msg.nonEmpty).mkString(CollectionTOCConstants.COMMA_SEPARATOR) if(invalidUnitLengthErrorMessage.trim.nonEmpty) - throw new ClientException("CSV_INVALID_FIELDS_LENGTH", s"Following rows have Unit's Name field exceeding maximum length of $maxUnitFieldLength characters: "+invalidUnitLengthErrorMessage) + throw new ClientException("CSV_INVALID_FIELDS_LENGTH", s"Following rows have invalid “Folder Nameâ€. The maximum length of characters should be $maxUnitFieldLength. Please correct and upload again: "+invalidUnitLengthErrorMessage) } private def validateDescFieldLength(csvRecords: util.List[CSVRecord]): Unit = { @@ -295,7 +295,7 @@ object CollectionCSVValidator { })}).filter(msg => msg.nonEmpty).mkString(CollectionTOCConstants.COMMA_SEPARATOR) if(invalidDescLengthErrorMessage.trim.nonEmpty) - throw new ClientException("CSV_INVALID_FIELDS_LENGTH", s"Following rows have 'Description' field exceeding maximum length of $maxDescFieldLength characters: "+invalidDescLengthErrorMessage) + throw new ClientException("CSV_INVALID_FIELDS_LENGTH", s"Following rows have invalid “Descriptionâ€. The maximum length of characters should be $maxDescFieldLength. Please correct and upload again "+invalidDescLengthErrorMessage) } private def validateUnitIdentifiers(csvRecords: util.List[CSVRecord], collectionHierarchy: Map[String, AnyRef]): Unit = { @@ -305,13 +305,13 @@ object CollectionCSVValidator { val invalidCollectionNodeIDErrorMessage = csvRecords.flatMap(csvRecord => { csvRecord.toMap.asScala.toMap.map(colData => { if (collectionNodeIdentifierHeader.contains(colData._1) && (colData._2.isEmpty || !collectionChildNodes.contains(colData._2.trim))) - MessageFormat.format("\nRow {0}", (csvRecord.getRecordNumber + 1).toString + " - " + colData._2) + MessageFormat.format("\nRow {0}", (csvRecord.getRecordNumber + 1).toString) else "" }) }).filter(msg => msg.nonEmpty).mkString(CollectionTOCConstants.COMMA_SEPARATOR) if (invalidCollectionNodeIDErrorMessage.trim.nonEmpty) - throw new ClientException("CSV_INVALID_COLLECTION_NODE_ID", "Following rows have invalid folder identifier: " + invalidCollectionNodeIDErrorMessage) + throw new ClientException("CSV_INVALID_COLLECTION_NODE_ID", "Following rows have invalid “Folder Identifierâ€. Please correct and upload again: " + invalidCollectionNodeIDErrorMessage) // validate Folder Identifier column in CSV - END TelemetryManager.log("CollectionCSVActor --> validateCSVRecordsDataAuthenticity --> after validating Folder Identifier column in CSV") } @@ -328,13 +328,13 @@ object CollectionCSVValidator { val invalidQRCodeErrorMessage = csvRecords.flatMap(csvRecord => { csvRecord.toMap.asScala.toMap.map(colData => { if (qrCodeHdrColsList.contains(colData._1) && (csvQRCodesList diff returnDIALCodes).contains(colData._2.trim)) - MessageFormat.format("\nRow {0}", (csvRecord.getRecordNumber + 1).toString + " - " + colData._2) + MessageFormat.format("\nRow {0}", (csvRecord.getRecordNumber + 1).toString) else "" }) }).filter(msg => msg.nonEmpty).mkString(CollectionTOCConstants.COMMA_SEPARATOR) if (invalidQRCodeErrorMessage.trim.nonEmpty) - throw new ClientException("CSV_INVALID_DIAL_CODES", "Following rows have invalid DIAL codes: " + invalidQRCodeErrorMessage) + throw new ClientException("CSV_INVALID_DIAL_CODES", "Following rows have invalid “QR Code†values. Please correct and upload again: " + invalidQRCodeErrorMessage) } // Validate QR Codes with reserved DIAL codes - END TelemetryManager.log("CollectionCSVActor --> validateCSVRecordsDataAuthenticity --> after validating QR Codes with reserved DIAL codes") @@ -377,7 +377,7 @@ object CollectionCSVValidator { }).filter(msg => msg.nonEmpty).mkString(CollectionTOCConstants.COMMA_SEPARATOR) if (invalidTopicsErrorMessage.trim.nonEmpty) - throw new ClientException("CSV_INVALID_MAPPED_TOPICS", "Following rows have invalid Mapped Topics: " + invalidTopicsErrorMessage) + throw new ClientException("CSV_INVALID_MAPPED_TOPICS", "Following rows have invalid “Mapped Topicsâ€. Please correct and upload again: " + invalidTopicsErrorMessage) } // Validate Mapped Topics with Collection Framework data - END TelemetryManager.log("CollectionCSVActor --> validateCSVRecordsDataAuthenticity --> after validating Mapped Topics with Collection Framework data") @@ -408,7 +408,7 @@ object CollectionCSVValidator { }).filter(msg => msg.nonEmpty).mkString(CollectionTOCConstants.COMMA_SEPARATOR) if (invalidLinkedContentsErrorMessage.trim.nonEmpty) - throw new ClientException("CSV_INVALID_LINKED_CONTENTS", "Following rows have invalid contents to link. Please check if the contents you are trying to link are Live/Published: " + invalidLinkedContentsErrorMessage) + throw new ClientException("CSV_INVALID_LINKED_CONTENTS", "Following rows have invalid linked contents. No live content found for the given do_id. Please correct and upload again: " + invalidLinkedContentsErrorMessage) TelemetryManager.log("CollectionCSVActor --> validateCSVRecordsDataAuthenticity --> after validating Linked Contents") returnedLinkedContentsResult -- GitLab