Skip to content
Snippets Groups Projects
Commit 174f44c6 authored by Sebastian Listl's avatar Sebastian Listl :speech_balloon:
Browse files

Merge branch '1088762-multipleDocumentDownload' into '2021.2'

[Projekt: Entwicklung - Neon][TicketNr.: 1088762][Download mehrerer Dateien...

See merge request xrm/basic!1497
parents a70a08c6 f2f5bbdb
No related branches found
No related tags found
No related merge requests found
import("ZippingUtil_lib");
import("Context_lib");
import("system.util");
import("system.translate");
......@@ -38,6 +39,7 @@ DocumentUtil.downloadSelectedDocuments = function(pAssignmentName) {
var fileNames = rows.map(function(value) {
return value["NAME"];
});
fileNames = ZippingUtil.renameDuplicateFilenamesForZip(fileNames);
neon.downloadToZip(translate.text("Files") + ".zip", binaryContents, fileNames);
}
else if(pAssignmentName == "ERRORLOG")
......
......@@ -261,7 +261,7 @@ Tester.prototype.equals = function(pExpect, pCustomDescription)
if(Utils.isObject(this.actualValue) || Utils.isObject(this.expectedValue))
{
this.expectedDisplayValue = JSON.stringify(this.actualValue, _getCircularReplacer());
this.expectedDisplayValue = Array.isArray(this.expectedValue) ? this.expectedValue : JSON.stringify(this.expectedValue, _getCircularReplacer());
this._testResult = Utils.isEqual(this.actualValue, this.expectedValue);
this._generateAssertDescription({custom: pCustomDescription, operator: "===", name: "Object value"});
}
......@@ -735,7 +735,7 @@ Tester.prototype.hasMaxLength = function(pExpect, pCustomDescription)
/**
* Test if a callback function throws an exception
*
* @param {Number} pExpect the expected error
* @param {Error} pExpect the expected error
* @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite
* @return {Tester}
*/
......
<?xml version="1.0" encoding="UTF-8"?>
<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.2" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.2">
<name>ZippingUtil_lib</name>
<majorModelMode>DISTRIBUTED</majorModelMode>
<documentation>%aditoprj%/process/ZippingUtil_lib/documentation.adoc</documentation>
<process>%aditoprj%/process/ZippingUtil_lib/process.js</process>
<variants>
<element>LIBRARY</element>
</variants>
</process>
Provides versatile utility functions for packing/unpacking zip-files.
\ No newline at end of file
import("system.translate");
/**
* Provides static methods for zipping/unzipping.
* Do not create an instance of this
*
* @class
* @static
*/
function ZippingUtil()
{
throw new Error(translate.text("[ZippingUtil.constructor]Cannot instantiate a static class."));
}
/**
* This function will determine duplicates in a list of filenames for a zip file and search for a matching, unique name for the duplicate. <br/>
* That is done by adding a number in bracets to the filename. That number is increased for each occurence and the first element ("the origin") is not
* changed at all.<br/>
* <br/>
* This function is perfect for preparing filenames for the neon.downloadToZip-Method, as the neon.downloadToZip would throw an error when filenames
* contain duplicates.<br/>
* <br/>
* Does not modify the input-array and if the input-array is emtpy a new empty array is returned.<br/>
*
* @param {Array} pFileNames Not nullable parameter to provide the filenames that are searched for duplicates.
* However it is not required that there are duplicates in the filelist. Example: ["offer.pdf", "offer.pdf"]
* @return {Array} Unique elements for the filenames; for the example of the pFileNames param this would be: ["offer.pdf", "offer(1).pdf"]. <br/>
* The amount of elements does not change, nor the position of the elements. Only duplicates are renamed.
*
* @throws <p><i>TypeError</i> when the pFileNames param is not an array or null.
* <br/> <i>Error</i> when the limit of possible filenames is reached, the current limit is 1024. This does prevent endless loops
* </p>
*/
ZippingUtil.renameDuplicateFilenamesForZip = function(pFileNames)
{
if (pFileNames == null || !Array.isArray(pFileNames))
{
throw new TypeError(translate.text("[ZippingUtil.renameDuplicateFilenamesForZip]FileNames type is invalid. An Array of filenames is required."));
}
if (pFileNames.length == 0)
{
return [];
}
var resultFileNameList = [];
var originFileNames = pFileNames; // this is only a reference -> do not modify this array!
// map to skip known duplicates (if a lot of files are named the same key); key: name of the originated filename, value: the POSSIBLE next version
var duplicationInfo = new Map();
// anonymous helper function to determine the next possible filename
var _findNextBestFilename = function(pFileName)
{
var additionalNo = duplicationInfo.has(pFileName) ? duplicationInfo.get(pFileName) : 0;
while (++additionalNo <= 1024) // 1024 is a random value we choosed to prevent endless attempts
{
// if we are in this function, the pFileName is already a duplicated entry, so we do NOT have to check this here at first
var firstDot = pFileName.indexOf("."); // first position because of filenames like "myFile.tar.gz"
var primaryFileName;
var secondaryFileName = "";
if (firstDot <= 0)
{
primaryFileName = pFileName;
}
else
{
primaryFileName = pFileName.substring(0, firstDot);
secondaryFileName = pFileName.substring(firstDot);
}
var composedFileName = primaryFileName + "(" + additionalNo + ")" + secondaryFileName;
duplicationInfo.set(pFileName, additionalNo);
if (!originFileNames.includes(composedFileName) && !resultFileNameList.includes(composedFileName))
{
return composedFileName
}
}
throw new Error(translate.text("[ZippingUtil.renameDuplicateFilenamesForZip]Limit for max length of filename iteration reached."));
}
for (var i = 0, l = originFileNames.length; i < l; i++)
{
var fileName = originFileNames[i];
if (resultFileNameList.includes(fileName))
{
// now there is a problem and we want to add a more specific version of the filename to be unique
resultFileNameList.push(_findNextBestFilename(fileName));
}
else
{
// all good
resultFileNameList.push(fileName);
}
}
return resultFileNameList;
}
<?xml version="1.0" encoding="UTF-8"?>
<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.2" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.2">
<name>ZippingUtil_test</name>
<title>[TEST] ZippingUtil_lib</title>
<majorModelMode>DISTRIBUTED</majorModelMode>
<icon>VAADIN:CHECK_CIRCLE</icon>
<process>%aditoprj%/process/ZippingUtil_test/process.js</process>
<variants>
<element>EXECUTABLE</element>
</variants>
</process>
import("system.translate");
import("system.result");
import("UnitTest_lib");
import("ZippingUtil_lib");
var constructorTests = new TestSuite("ZippingUtil.constructor", [
new Test("should throw exception when trying to instantiate",
function(pTester) {
var expected = new Error(translate.text("[ZippingUtil.constructor]Cannot instantiate a static class."));
// do be able to catch the exception it is required to determine the actual value in a callback function
pTester.expectThat(function (){
return new ZippingUtil();
}).throwsException(expected).assert();
}
)
]);
var extendFlatFilesTests = new TestSuite("ZippingUtil.renameDuplicateFilenamesForZip", [
new Test("should not modify unique filenames",
function(pTester) {
var fileNameInput = ["file1.pdf", "file2.pdf", "file3.pdf"];
var actualValue = ZippingUtil.renameDuplicateFilenamesForZip(fileNameInput);
pTester.expectThat(actualValue).isArray().assert();
pTester.expectThat(actualValue).equals(fileNameInput).assert();
}
),
new Test("should return empty array when zero filenames are given",
function(pTester) {
var fileNameInput = [];
var actualValue = ZippingUtil.renameDuplicateFilenamesForZip(fileNameInput);
pTester.expectThat(actualValue).isArray().assert();
pTester.expectThat(actualValue).equals([]).assert();
}
),
new Test("should modify duplicate filenames (where duplicated entries do not already exist)",
function(pTester) {
var fileNameInput = ["file1.pdf", "file1.pdf", "file1.pdf", "file2.pdf"];
var expectedResult = ["file1.pdf", "file1(1).pdf", "file1(2).pdf", "file2.pdf"];
var actualValue = ZippingUtil.renameDuplicateFilenamesForZip(fileNameInput);
pTester.expectThat(actualValue).isArray().assert();
pTester.expectThat(actualValue).equals(expectedResult).assert();
}
),
new Test("should modify duplicate filenames (where duplicated entries do already exist once)",
function(pTester) {
var fileNameInput = ["file1.pdf", "file1.pdf", "file1(1).pdf", "file2.pdf"];
var expectedResult = ["file1.pdf", "file1(2).pdf", "file1(1).pdf", "file2.pdf"];
var actualValue = ZippingUtil.renameDuplicateFilenamesForZip(fileNameInput);
pTester.expectThat(actualValue).isArray().assert();
pTester.expectThat(actualValue).equals(expectedResult).assert();
}
),
new Test("should modify duplicate filenames (where duplicated entries do already exist several times)",
function(pTester) {
var fileNameInput = ["file1(1).pdf", "file1(1).pdf", "file1(1).pdf", "file2.pdf"];
var expectedResult = ["file1(1).pdf", "file1(1)(1).pdf", "file1(1)(2).pdf", "file2.pdf"];
var actualValue = ZippingUtil.renameDuplicateFilenamesForZip(fileNameInput);
pTester.expectThat(actualValue).isArray().assert();
pTester.expectThat(actualValue).equals(expectedResult).assert();
}
),
new Test("should throw exception when no array is passed as filenames",
function(pTester) {
var fileNameInput = "not an array";
var expected = new TypeError(translate.text("[ZippingUtil.renameDuplicateFilenamesForZip]FileNames type is invalid. An Array of filenames is required."));
// do be able to catch the exception it is required to determine the actual value in a callback function
pTester.expectThat(function (){
return ZippingUtil.renameDuplicateFilenamesForZip(fileNameInput);
}).throwsException(expected).assert();
}
),
new Test("should throw exception when null is passed as filenames",
function(pTester) {
var fileNameInput = null;
var expected = new TypeError(translate.text("[ZippingUtil.renameDuplicateFilenamesForZip]FileNames type is invalid. An Array of filenames is required."));
// do be able to catch the exception it is required to determine the actual value in a callback function
pTester.expectThat(function (){
return ZippingUtil.renameDuplicateFilenamesForZip(fileNameInput);
}).throwsException(expected).assert();
}
),
new Test("should rename files without filextension",
function(pTester) {
var fileNameInput = ["file1", "file1", "file1", "file2"];
var expectedResult = ["file1", "file1(1)", "file1(2)", "file2"];
var actualValue = ZippingUtil.renameDuplicateFilenamesForZip(fileNameInput);
pTester.expectThat(actualValue).isArray().assert();
pTester.expectThat(actualValue).equals(expectedResult).assert();
}
),
new Test("should throw error when limit of loop renamings are exceeded",
function(pTester) {
var fileNameInput = new Array(1025 + 1).fill("filename.pdf");//"+ 1" because the first filename is always kept the same
var expected = new Error(translate.text("[ZippingUtil.renameDuplicateFilenamesForZip]Limit for max length of filename iteration reached."));
// do be able to catch the exception it is required to determine the actual value in a callback function
pTester.expectThat(function (){
var res = ZippingUtil.renameDuplicateFilenamesForZip(fileNameInput);
return res;
}).throwsException(expected).assert();
}
),
new Test("should split at correct dot of file extension",
function(pTester) {
var fileNameInput = ["file1.tar.gz", "file1.tar.gz"];
var expectedResult = ["file1.tar.gz", "file1(1).tar.gz"];
var actualValue = ZippingUtil.renameDuplicateFilenamesForZip(fileNameInput);
pTester.expectThat(actualValue).isArray().assert();
pTester.expectThat(actualValue).equals(expectedResult).assert();
}
),
new Test("should handle filenames with starting dot",
function(pTester) {
var fileNameInput = [".file1", ".file1", "...", "..."];
var expectedResult = [".file1", ".file1(1)", "...", "...(1)"];
var actualValue = ZippingUtil.renameDuplicateFilenamesForZip(fileNameInput);
pTester.expectThat(actualValue).isArray().assert();
pTester.expectThat(actualValue).equals(expectedResult).assert();
}
)
]);
var tester = new Tester("Test ZippingUtil_lib");
tester.initCoverage(ZippingUtil);
tester.test(constructorTests);
tester.test(extendFlatFilesTests);
tester.summary();
result.object(tester.getResults());
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment