This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository coselmar. See https://gitlab.nuiton.org/codelutin/coselmar.git commit 54c521e542f06fa7db6f56d1ff72213834ff4b06 Author: Yannick Martel <martel@©odelutin.com> Date: Fri Jun 9 15:46:38 2017 +0200 refs #9206 Add externalUrl management --- .../coselmar/beans/DocumentImportModel.java | 1 + .../beans/MassiveDocumentsImportResult.java | 16 ++++ .../coselmar/services/v1/DocumentsWebService.java | 83 ++++++++++++--------- .../services/v1/DocumentsWebServiceTest.java | 5 +- coselmar-rest/src/test/resources/documents.zip | Bin 151809 -> 188296 bytes .../src/test/resources/documents_errors.zip | Bin 87774 -> 87833 bytes coselmar-ui/src/main/webapp/i18n/en.js | 8 +- coselmar-ui/src/main/webapp/i18n/fr.js | 6 +- 8 files changed, 78 insertions(+), 41 deletions(-) diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/DocumentImportModel.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/DocumentImportModel.java index d70af0b..b19a77f 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/DocumentImportModel.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/DocumentImportModel.java @@ -40,6 +40,7 @@ public class DocumentImportModel extends AbstractImportModel<DocumentBean> { newOptionalColumn("comment", "comment"); newMandatoryColumn("citation", "citation"); newMandatoryColumn("fileName", "fileName"); + newMandatoryColumn("externalUrl", "externalUrl"); } @Override diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/MassiveDocumentsImportResult.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/MassiveDocumentsImportResult.java index 29bdc91..98436e8 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/MassiveDocumentsImportResult.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/MassiveDocumentsImportResult.java @@ -10,11 +10,13 @@ public class MassiveDocumentsImportResult { protected boolean success = true; protected List<String> missingFiles; + protected List<String> documentsWithoutAttachment; protected boolean errorSystem; protected ImportSystemErrorType systemErrorType; public MassiveDocumentsImportResult() { this.missingFiles = new ArrayList<>(); + this.documentsWithoutAttachment = new ArrayList<>(); } public boolean isSuccess() { @@ -35,6 +37,20 @@ public class MassiveDocumentsImportResult { this.success = false; } + public List<String> getDocumentsWithoutAttachment() { + return documentsWithoutAttachment; + } + + public void setDocumentsWithoutAttachment(List<String> documentsWithoutAttachment) { + this.success = false; + this.documentsWithoutAttachment = documentsWithoutAttachment; + } + + public void addDocumentWithoutAttachment(String documentWithoutAttachment) { + this.success = false; + this.documentsWithoutAttachment.add(documentWithoutAttachment); + } + public boolean isErrorSystem() { return errorSystem; } diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/DocumentsWebService.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/DocumentsWebService.java index 93e4b24..939f38e 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/DocumentsWebService.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/DocumentsWebService.java @@ -1021,55 +1021,68 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { // ... and read each entries and retrieve associated File try { for (DocumentBean documentBean : importer) { - FileInfos fileInfos = new FileInfos(); - String fileName = StringUtils.strip(documentBean.getFileName()); // cf https://forge.codelutin.com/issues/9205?issue_count=18&issue_position=4&next_issue_id=9198&prev_issue_id=9206#note-2 documentBean.setPrivacy(Privacy.PUBLIC.name()); + String externalUrl = documentBean.getExternalUrl(); + String fileName = StringUtils.strip(documentBean.getFileName()); - ZipEntry zipFileEntry = zipFile.getEntry(fileName); - if (zipFileEntry == null) { - importResult.addMissingFile(fileName); - - } else { - try { - InputStream zipFileInputStream = zipFile.getInputStream(zipFileEntry); - fileInfos.setFileName(fileName); - String fileMimeType = TikaUtils.getFileMimeType(fileName); - String futureFilePath = getDocumentFileDestPath(currentUser, fileName); - - String storageFileName = getFileStorageName(fileName); - - // Push file stream in temporary folder - File zipEntryFile = new File(zipTempPath + File.separator + storageFileName); - zipEntryFile.createNewFile(); - Files.copy(zipFileInputStream, zipEntryFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + FileInfos fileInfos = null; + boolean documentOk = true; + // We must have at least an external URL or a file with the document + if (StringUtils.isBlank(externalUrl) && StringUtils.isBlank(fileName)) { + importResult.addDocumentWithoutAttachment(documentBean.getName()); - // Create fileInfos - fileInfos.setFileName(fileName); - fileInfos.setFinalFilePath(futureFilePath); - fileInfos.setActualFilePath(zipEntryFile.getAbsolutePath()); - fileInfos.setMimeType(fileMimeType); + } else if (StringUtils.isNotBlank(fileName)) { + fileInfos = new FileInfos(); - // Create document - createDocument(documentBean, fileInfos, currentUser); + ZipEntry zipFileEntry = zipFile.getEntry(fileName); + if (zipFileEntry == null) { + importResult.addMissingFile(fileName); + documentOk = false; + } else { try { - zipFileInputStream.close(); + InputStream zipFileInputStream = zipFile.getInputStream(zipFileEntry); + String fileMimeType = TikaUtils.getFileMimeType(fileName); + String futureFilePath = getDocumentFileDestPath(currentUser, fileName); + + String storageFileName = getFileStorageName(fileName); + + // Push file stream in temporary folder + File zipEntryFile = new File(zipTempPath + File.separator + storageFileName); + zipEntryFile.createNewFile(); + Files.copy(zipFileInputStream, zipEntryFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + + // Create fileInfos + fileInfos.setFileName(fileName); + fileInfos.setFinalFilePath(futureFilePath); + fileInfos.setActualFilePath(zipEntryFile.getAbsolutePath()); + fileInfos.setMimeType(fileMimeType); + + try { + zipFileInputStream.close(); + } catch (IOException e) { + if (log.isErrorEnabled()) { + log.error("Unable to close stream from ZipEntry : " + fileName, e); + } + } } catch (IOException e) { + String message = String.format("Unable to retrieve '%s' from zip file", fileName); if (log.isErrorEnabled()) { - log.error("Unable to close stream from ZipEntry : " + fileName, e); + log.error(message, e); } + importResult.setSystemErrorType(MassiveDocumentsImportResult.ImportSystemErrorType.UNABLE_TO_READ_ZIP_ENTRY); + importResult.addMissingFile(fileName); + documentOk = false; } - } catch (IOException e) { - String message = String.format("Unable to retrieve '%s' from zip file", fileName); - if (log.isErrorEnabled()) { - log.error(message, e); - } - importResult.setSystemErrorType(MassiveDocumentsImportResult.ImportSystemErrorType.UNABLE_TO_READ_ZIP_ENTRY); - importResult.addMissingFile(fileName); } } + // Create document + if (documentOk) { + createDocument(documentBean, fileInfos, currentUser); + } + } } catch (ImportRuntimeException ire) { if (log.isErrorEnabled()) { diff --git a/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/v1/DocumentsWebServiceTest.java b/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/v1/DocumentsWebServiceTest.java index ca3562c..04ea309 100644 --- a/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/v1/DocumentsWebServiceTest.java +++ b/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/v1/DocumentsWebServiceTest.java @@ -86,7 +86,7 @@ public class DocumentsWebServiceTest extends AbstractCoselmarServiceTest { Assert.assertTrue(importResult.getMissingFiles().isEmpty()); DocumentTopiaDao documentDao = getServiceContext().getPersistenceContext().getDocumentDao(); List<Document> documents = documentDao.findAll(); - Assert.assertEquals(3, documents.size()); + Assert.assertEquals(4, documents.size()); String oneFilePath = documents.get(0).getFilePath(); File oneFile = new File(oneFilePath); Assert.assertTrue(oneFile.exists()); @@ -116,6 +116,9 @@ public class DocumentsWebServiceTest extends AbstractCoselmarServiceTest { Assert.assertFalse(importResult.getMissingFiles().isEmpty()); Assert.assertEquals(1, importResult.getMissingFiles().size()); Assert.assertEquals("Reunion-v0.3.pdf", importResult.getMissingFiles().get(0)); + Assert.assertFalse(importResult.getDocumentsWithoutAttachment().isEmpty()); + Assert.assertEquals(1, importResult.getDocumentsWithoutAttachment().size()); + Assert.assertEquals("Lutin", importResult.getDocumentsWithoutAttachment().get(0)); // Should import have been rollback DocumentTopiaDao documentDao = getServiceContext().getPersistenceContext().getDocumentDao(); List<Document> documents = documentDao.findAll(); diff --git a/coselmar-rest/src/test/resources/documents.zip b/coselmar-rest/src/test/resources/documents.zip index ad0f982..039ba61 100644 Binary files a/coselmar-rest/src/test/resources/documents.zip and b/coselmar-rest/src/test/resources/documents.zip differ diff --git a/coselmar-rest/src/test/resources/documents_errors.zip b/coselmar-rest/src/test/resources/documents_errors.zip index de38463..7ab9e49 100644 Binary files a/coselmar-rest/src/test/resources/documents_errors.zip and b/coselmar-rest/src/test/resources/documents_errors.zip differ diff --git a/coselmar-ui/src/main/webapp/i18n/en.js b/coselmar-ui/src/main/webapp/i18n/en.js index f383a80..42b8814 100644 --- a/coselmar-ui/src/main/webapp/i18n/en.js +++ b/coselmar-ui/src/main/webapp/i18n/en.js @@ -338,9 +338,9 @@ var translateEN = { This file is UTF-8 encoded and using ';' as separator</li>\ <li>all document files described in 'description.csv'.</li>\ </ul>\ - Name of the zip filz is free.\ + Name of the zip file is free.\ </p>\ - <p>The 'description.csv' file should contain following columns (* = mandatory fields) : \ + <p>The 'description.csv' file should contain following columns (* = mandatory columns) : \ <ul>\ <li><strong>name*</strong> : document title (field Title)</li>\ <li><strong>type*</strong> : document type (field Type) only with values described in next paragraph</li>\ @@ -353,7 +353,8 @@ var translateEN = { <li><strong>language</strong> : document language</li>\ <li><strong>comment</strong> : comment (field Comment)</li>\ <li><strong>citation*</strong> : citation (field Citation)</li>\ - <li><strong>fileName*</strong> : linked file name (must be exactly same as in the zip)</li>\ + <li><strong>fileName*</strong> : linked file name (must be exactly same as in the zip ; could be empty if externalUrl given)</li>\ + <li><strong>externalUrl*</strong> : external url (without 'http://' ; could be empty if fileName given)</li>\ </ul>\ Different values allowed for document <strong>Type</strong> are :\ <ul>\ @@ -372,6 +373,7 @@ var translateEN = { <li><strong>DATA</strong></li>\ <li><strong>OTHER</strong></li>\ </ul>\ + Note that all created documents will be <strong>public</strong>\ </p>", //Common part diff --git a/coselmar-ui/src/main/webapp/i18n/fr.js b/coselmar-ui/src/main/webapp/i18n/fr.js index 1b5d07d..28e87fb 100644 --- a/coselmar-ui/src/main/webapp/i18n/fr.js +++ b/coselmar-ui/src/main/webapp/i18n/fr.js @@ -342,7 +342,7 @@ var translateFR = { </ul>\ Le nom du fichier Zip est libre.\ </p>\ - <p>Le fichier description.csv contiendra les colonnes suivantes (* = champs obligatoires) : \ + <p>Le fichier description.csv contiendra les colonnes suivantes (* = colonnes obligatoires) : \ <ul>\ <li><strong>name*</strong> : titre du document (champ Title)</li>\ <li><strong>type*</strong> : type de document (champ Type) aux valeurs décrites ci-après</li>\ @@ -355,7 +355,8 @@ var translateFR = { <li><strong>language</strong> : langue du document (champ Langue)</li>\ <li><strong>comment</strong> : commentaire (champ Comment)</li>\ <li><strong>citation*</strong> : citation (champ Citation)</li>\ - <li><strong>fileName*</strong> : nom du fichier lié (doit être exactement le même que dans le zip)</li>\ + <li><strong>fileName*</strong> : nom du fichier lié (doit être exactement le même que dans le zip ; peut être vide si externalUrl fournie)</li>\ + <li><strong>externalUrl*</strong> : url externe (sans le 'http://' ; peut être vide si le fileName est fourni)</li>\ </ul>\ Les différentes valeurs possibles pour le <strong>Type</strong> de document sont :\ <ul>\ @@ -374,6 +375,7 @@ var translateFR = { <li><strong>DATA</strong> (données)</li>\ <li><strong>OTHER</strong> (autre)</li>\ </ul>\ + À noter que les documents créés seront <strong>visibles pour tous</strong>.\ </p>", //Common part -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.