diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/DocumentDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/DocumentDao.java index 8f7ac022..9ce799e7 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/DocumentDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/DocumentDao.java @@ -10,6 +10,7 @@ import com.sismics.util.context.ThreadLocalContext; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.Query; +import javax.persistence.TypedQuery; import java.sql.Timestamp; import java.util.Date; import java.util.List; @@ -50,10 +51,9 @@ public class DocumentDao { * @param limit Limit * @return List of documents */ - @SuppressWarnings("unchecked") public List findAll(int offset, int limit) { EntityManager em = ThreadLocalContext.get().getEntityManager(); - Query q = em.createQuery("select d from Document d where d.deleteDate is null"); + TypedQuery q = em.createQuery("select d from Document d where d.deleteDate is null", Document.class); q.setFirstResult(offset); q.setMaxResults(limit); return q.getResultList(); @@ -65,10 +65,9 @@ public class DocumentDao { * @param userId User ID * @return List of documents */ - @SuppressWarnings("unchecked") public List findByUserId(String userId) { EntityManager em = ThreadLocalContext.get().getEntityManager(); - Query q = em.createQuery("select d from Document d where d.userId = :userId and d.deleteDate is null"); + TypedQuery q = em.createQuery("select d from Document d where d.userId = :userId and d.deleteDate is null", Document.class); q.setParameter("userId", userId); return q.getResultList(); } @@ -138,16 +137,16 @@ public class DocumentDao { EntityManager em = ThreadLocalContext.get().getEntityManager(); // Get the document - Query q = em.createQuery("select d from Document d where d.id = :id and d.deleteDate is null"); - q.setParameter("id", id); - Document documentDb = (Document) q.getSingleResult(); + TypedQuery dq = em.createQuery("select d from Document d where d.id = :id and d.deleteDate is null", Document.class); + dq.setParameter("id", id); + Document documentDb = dq.getSingleResult(); // Delete the document Date dateNow = new Date(); documentDb.setDeleteDate(dateNow); // Delete linked data - q = em.createQuery("update File f set f.deleteDate = :dateNow where f.documentId = :documentId and f.deleteDate is null"); + Query q = em.createQuery("update File f set f.deleteDate = :dateNow where f.documentId = :documentId and f.deleteDate is null"); q.setParameter("documentId", id); q.setParameter("dateNow", dateNow); q.executeUpdate(); @@ -179,10 +178,10 @@ public class DocumentDao { */ public Document getById(String id) { EntityManager em = ThreadLocalContext.get().getEntityManager(); - Query q = em.createQuery("select d from Document d where d.id = :id and d.deleteDate is null"); + TypedQuery q = em.createQuery("select d from Document d where d.id = :id and d.deleteDate is null", Document.class); q.setParameter("id", id); try { - return (Document) q.getSingleResult(); + return q.getSingleResult(); } catch (NoResultException e) { return null; } @@ -199,9 +198,9 @@ public class DocumentDao { EntityManager em = ThreadLocalContext.get().getEntityManager(); // Get the document - Query q = em.createQuery("select d from Document d where d.id = :id and d.deleteDate is null"); + TypedQuery q = em.createQuery("select d from Document d where d.id = :id and d.deleteDate is null", Document.class); q.setParameter("id", document.getId()); - Document documentDb = (Document) q.getSingleResult(); + Document documentDb = q.getSingleResult(); // Update the document documentDb.setTitle(document.getTitle()); @@ -237,7 +236,6 @@ public class DocumentDao { query.setParameter("fileId", document.getFileId()); query.setParameter("id", document.getId()); query.executeUpdate(); - } /** diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/FileDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/FileDao.java index 633d939e..11803fb8 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/FileDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/FileDao.java @@ -68,21 +68,32 @@ public class FileDao { q.setParameter("userId", userId); return q.getResultList(); } + + /** + * Returns a list of active files. + * + * @param ids Files IDs + * @return List of files + */ + public List getFiles(List ids) { + EntityManager em = ThreadLocalContext.get().getEntityManager(); + TypedQuery q = em.createQuery("select f from File f where f.id in :ids and f.deleteDate is null", File.class); + q.setParameter("ids", ids); + return q.getResultList(); + } /** - * Returns an active file. + * Returns an active file or null. * * @param id File ID * @return File */ public File getFile(String id) { - EntityManager em = ThreadLocalContext.get().getEntityManager(); - TypedQuery q = em.createQuery("select f from File f where f.id = :id and f.deleteDate is null", File.class); - q.setParameter("id", id); - try { - return q.getSingleResult(); - } catch (NoResultException e) { + List files = getFiles(List.of(id)); + if (files.isEmpty()) { return null; + } else { + return files.get(0); } } diff --git a/docs-web-common/src/test/java/com/sismics/docs/rest/BaseJerseyTest.java b/docs-web-common/src/test/java/com/sismics/docs/rest/BaseJerseyTest.java index 1b764e73..0d8bcc57 100644 --- a/docs-web-common/src/test/java/com/sismics/docs/rest/BaseJerseyTest.java +++ b/docs-web-common/src/test/java/com/sismics/docs/rest/BaseJerseyTest.java @@ -34,6 +34,16 @@ import java.util.Objects; * @author jtremeaux */ public abstract class BaseJerseyTest extends JerseyTest { + protected static final String FILE_APACHE_PPTX = "file/apache.pptx"; + protected static final String FILE_DOCUMENT_DOCX = "file/document.docx"; + protected static final String FILE_DOCUMENT_ODT = "file/document.odt"; + protected static final String FILE_DOCUMENT_TXT = "file/document.txt"; + protected static final String FILE_EINSTEIN_ROOSEVELT_LETTER_PNG = "file/Einstein-Roosevelt-letter.png"; + protected static final String FILE_PIA_00452_JPG = "file/PIA00452.jpg"; + protected static final String FILE_VIDEO_WEBM = "file/video.webm"; + protected static final String FILE_WIKIPEDIA_PDF = "file/wikipedia.pdf"; + protected static final String FILE_WIKIPEDIA_ZIP = "file/wikipedia.zip"; + /** * Test HTTP server. */ diff --git a/docs-web-common/src/test/java/com/sismics/docs/rest/util/ClientUtil.java b/docs-web-common/src/test/java/com/sismics/docs/rest/util/ClientUtil.java index 51972eee..333fca60 100644 --- a/docs-web-common/src/test/java/com/sismics/docs/rest/util/ClientUtil.java +++ b/docs-web-common/src/test/java/com/sismics/docs/rest/util/ClientUtil.java @@ -3,6 +3,7 @@ package com.sismics.docs.rest.util; import com.google.common.io.Resources; import com.sismics.util.filter.TokenBasedSecurityFilter; import org.glassfish.jersey.media.multipart.FormDataMultiPart; +import org.glassfish.jersey.media.multipart.MultiPart; import org.glassfish.jersey.media.multipart.MultiPartFeature; import org.glassfish.jersey.media.multipart.file.StreamDataBodyPart; import org.junit.Assert; @@ -16,6 +17,12 @@ import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.Response; import java.io.IOException; import java.io.InputStream; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Date; /** * REST client utilities. @@ -156,27 +163,58 @@ public class ClientUtil { return authToken; } + /** + * Create a document + * + * @param token Authentication token + * @return Document ID + */ + public String createDocument(String token) { + JsonObject json = this.resource.path("/document").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, token) + .put(Entity.form(new Form() + .param("title", "Document Title") + .param("description", "Document description") + .param("language", "eng") + .param("create_date", Long.toString(new Date().getTime()))), JsonObject.class); + String documentId = json.getString("id"); + Assert.assertNotNull(documentId); + return documentId; + } + /** * Add a file to a document. * * @param file File path - * @param filename Filename * @param token Authentication token * @param documentId Document ID * @return File ID * @throws IOException e + * @throws URISyntaxException e */ - public String addFileToDocument(String file, String filename, String token, String documentId) throws IOException { - try (InputStream is = Resources.getResource(file).openStream()) { + public String addFileToDocument(String file, String token, String documentId) throws IOException, URISyntaxException { + URL fileResource = Resources.getResource(file); + Path filePath = Paths.get(fileResource.toURI()); + String filename = filePath.getFileName().toString(); + try (InputStream is = fileResource.openStream()) { StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, filename); try (FormDataMultiPart multiPart = new FormDataMultiPart()) { - JsonObject json = resource + MultiPart formContent; + if (documentId != null) { + formContent = multiPart.field("id", documentId).bodyPart(streamDataBodyPart); + } else { + formContent = multiPart.bodyPart(streamDataBodyPart); + } + JsonObject json = this.resource .register(MultiPartFeature.class) .path("/file").request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, token) - .put(Entity.entity(multiPart.field("id", documentId).bodyPart(streamDataBodyPart), + .put(Entity.entity(formContent, MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class); - return json.getString("id"); + String fileId = json.getString("id"); + Assert.assertNotNull(fileId); + Assert.assertEquals(Files.size(filePath), json.getJsonNumber("size").longValue()); + return fileId; } } } diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/BaseResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/BaseResource.java index 8fb8d4c6..369467e9 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/BaseResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/BaseResource.java @@ -9,6 +9,7 @@ import com.sismics.util.filter.SecurityFilter; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; +import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; @@ -22,6 +23,7 @@ import java.util.Set; * @author jtremeaux */ @Consumes(MediaType.APPLICATION_FORM_URLENCODED) +@Produces(MediaType.APPLICATION_JSON) public abstract class BaseResource { /** * @apiDefine admin Admin diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/DocsMessageBodyWriter.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/DocsMessageBodyWriter.java new file mode 100644 index 00000000..acb4ba99 --- /dev/null +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/DocsMessageBodyWriter.java @@ -0,0 +1,34 @@ +package com.sismics.docs.rest.resource; + +import org.glassfish.jersey.message.internal.ReaderWriter; + +import javax.json.JsonObject; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.Provider; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +/** + * When a JSON-based exception is thrown but a JSON response is not expected, + * set the media type of the response as plain text. + */ +@Provider +@Produces(MediaType.APPLICATION_OCTET_STREAM) +public class DocsMessageBodyWriter implements MessageBodyWriter { + + @Override + public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return true; + } + + @Override + public void writeTo(JsonObject o, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { + ReaderWriter.writeToAsString(o.toString(), entityStream, MediaType.TEXT_PLAIN_TYPE); + } +} diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/FileResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/FileResource.java index c7ea3e88..dea0ef39 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/FileResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/FileResource.java @@ -575,6 +575,7 @@ public class FileResource extends BaseResource { */ @GET @Path("{id: [a-z0-9\\-]+}/data") + @Produces(MediaType.APPLICATION_OCTET_STREAM) public Response data( @PathParam("id") final String fileId, @QueryParam("share") String shareId, @@ -664,23 +665,24 @@ public class FileResource extends BaseResource { /** * Returns all files from a document, zipped. * - * @api {get} /file/zip Get zipped files + * @api {get} /file/zip Returns all files from a document, zipped. * @apiName GetFileZip * @apiGroup File * @apiParam {String} id Document ID * @apiParam {String} share Share ID * @apiSuccess {Object} file The ZIP file is the whole response - * @apiError (client) NotFound Document not found + * @apiError (client) NotFoundException Document not found * @apiError (server) InternalServerError Error creating the ZIP file * @apiPermission none * @apiVersion 1.5.0 * * @param documentId Document ID + * @param shareId Share ID * @return Response */ @GET @Path("zip") - @Produces(MediaType.APPLICATION_OCTET_STREAM) + @Produces({MediaType.APPLICATION_OCTET_STREAM, MediaType.TEXT_PLAIN}) public Response zip( @QueryParam("id") String documentId, @QueryParam("share") String shareId) { @@ -692,12 +694,46 @@ public class FileResource extends BaseResource { if (documentDto == null) { throw new NotFoundException(); } - - // Get files and user associated with this document + + // Get files associated with this document FileDao fileDao = new FileDao(); - final UserDao userDao = new UserDao(); final List fileList = fileDao.getByDocumentId(principal.getId(), documentId); - + String zipFileName = documentDto.getTitle().replaceAll("\\W+", "_"); + return sendZippedFiles(zipFileName, fileList); + } + + /** + * Returns a list of files, zipped + * + * @api {post} /file/zip Returns a list of files, zipped + * @apiName GetFilesZip + * @apiGroup File + * @apiParam {String[]} files IDs + * @apiSuccess {Object} file The ZIP file is the whole response + * @apiError (client) NotFoundException Files not found + * @apiError (server) InternalServerError Error creating the ZIP file + * @apiPermission none + * @apiVersion 1.11.0 + * + * @param filesIdsList Files IDs + * @return Response + */ + @POST + @Path("zip") + @Produces({MediaType.APPLICATION_OCTET_STREAM, MediaType.TEXT_PLAIN}) + public Response zip( + @FormParam("files") List filesIdsList) { + authenticate(); + List fileList = findFiles(filesIdsList); + return sendZippedFiles("files", fileList); + } + + /** + * Sent the content of a list of files. + */ + private Response sendZippedFiles(String zipFileName, List fileList) { + final UserDao userDao = new UserDao(); + // Create the ZIP stream StreamingOutput stream = outputStream -> { try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) { @@ -727,7 +763,7 @@ public class FileResource extends BaseResource { // Write to the output return Response.ok(stream) .header("Content-Type", "application/zip") - .header("Content-Disposition", "attachment; filename=\"" + documentDto.getTitle().replaceAll("\\W+", "_") + ".zip\"") + .header("Content-Disposition", "attachment; filename=\"" + zipFileName + ".zip\"") .build(); } @@ -744,7 +780,32 @@ public class FileResource extends BaseResource { if (file == null) { throw new NotFoundException(); } + checkFileAccessible(shareId, file); + return file; + } + + /** + * Find a list of files with access rights checking. + * + * @param filesIds Files IDs + * @return List + */ + private List findFiles(List filesIds) { + FileDao fileDao = new FileDao(); + List files = fileDao.getFiles(filesIds); + for (File file : files) { + checkFileAccessible(null, file); + } + return files; + } + + /** + * Check if a file is accessible to the current user + * @param shareId Share ID + * @param file + */ + private void checkFileAccessible(String shareId, File file) { if (file.getDocumentId() == null) { // It's an orphan file if (!file.getUserId().equals(principal.getId())) { @@ -758,6 +819,5 @@ public class FileResource extends BaseResource { throw new ForbiddenClientException(); } } - return file; } } diff --git a/docs-web/src/test/java/com/sismics/docs/rest/TestAuditLogResource.java b/docs-web/src/test/java/com/sismics/docs/rest/TestAuditLogResource.java index d8efd589..5dcb6435 100644 --- a/docs-web/src/test/java/com/sismics/docs/rest/TestAuditLogResource.java +++ b/docs-web/src/test/java/com/sismics/docs/rest/TestAuditLogResource.java @@ -99,7 +99,7 @@ public class TestAuditLogResource extends BaseJerseyTest { long update1Date = json.getJsonNumber("update_date").longValue(); // Add a file to the document - clientUtil.addFileToDocument("file/wikipedia.pdf", "wikipedia.pdf", auditlog1Token, document1Id); + clientUtil.addFileToDocument(FILE_WIKIPEDIA_PDF, auditlog1Token, document1Id); // Get document 1 json = target().path("/document/" + document1Id).request() @@ -136,4 +136,4 @@ public class TestAuditLogResource extends BaseJerseyTest { } return count; } -} \ No newline at end of file +} diff --git a/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java b/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java index 13468a0e..f97644eb 100644 --- a/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java +++ b/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java @@ -96,8 +96,8 @@ public class TestDocumentResource extends BaseJerseyTest { Assert.assertNotNull(document2Id); // Add a file - String file1Id = clientUtil.addFileToDocument("file/Einstein-Roosevelt-letter.png", - "Einstein-Roosevelt-letter.png", document1Token, document1Id); + String file1Id = clientUtil.addFileToDocument(FILE_EINSTEIN_ROOSEVELT_LETTER_PNG, + document1Token, document1Id); // Share this document target().path("/share").request() @@ -151,8 +151,8 @@ public class TestDocumentResource extends BaseJerseyTest { Assert.assertNotNull(document3Id); // Add a file - clientUtil.addFileToDocument("file/Einstein-Roosevelt-letter.png", - "Einstein-Roosevelt-letter.png", document3Token, document3Id); + clientUtil.addFileToDocument(FILE_EINSTEIN_ROOSEVELT_LETTER_PNG, + document3Token, document3Id); // List all documents from document3 json = target().path("/document/list") @@ -444,22 +444,13 @@ public class TestDocumentResource extends BaseJerseyTest { String documentOdtToken = clientUtil.login("document_odt"); // Create a document - long create1Date = new Date().getTime(); - JsonObject json = target().path("/document").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, documentOdtToken) - .put(Entity.form(new Form() - .param("title", "My super title document 1") - .param("description", "My super description for document 1") - .param("language", "eng") - .param("create_date", Long.toString(create1Date))), JsonObject.class); - String document1Id = json.getString("id"); - Assert.assertNotNull(document1Id); + String document1Id = clientUtil.createDocument(documentOdtToken); // Add a PDF file - String file1Id = clientUtil.addFileToDocument("file/document.odt", "document.odt", documentOdtToken, document1Id); + String file1Id = clientUtil.addFileToDocument(FILE_DOCUMENT_ODT, documentOdtToken, document1Id); // Search documents by query in full content - json = target().path("/document/list") + JsonObject json = target().path("/document/list") .queryParam("search", "full:ipsum") .request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, documentOdtToken) @@ -504,22 +495,13 @@ public class TestDocumentResource extends BaseJerseyTest { String documentDocxToken = clientUtil.login("document_docx"); // Create a document - long create1Date = new Date().getTime(); - JsonObject json = target().path("/document").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, documentDocxToken) - .put(Entity.form(new Form() - .param("title", "My super title document 1") - .param("description", "My super description for document 1") - .param("language", "eng") - .param("create_date", Long.toString(create1Date))), JsonObject.class); - String document1Id = json.getString("id"); - Assert.assertNotNull(document1Id); + String document1Id = clientUtil.createDocument(documentDocxToken); // Add a PDF file - String file1Id = clientUtil.addFileToDocument("file/document.docx", "document.docx", documentDocxToken, document1Id); + String file1Id = clientUtil.addFileToDocument(FILE_DOCUMENT_DOCX, documentDocxToken, document1Id); // Search documents by query in full content - json = target().path("/document/list") + JsonObject json = target().path("/document/list") .queryParam("search", "full:dolor") .request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, documentDocxToken) @@ -564,22 +546,13 @@ public class TestDocumentResource extends BaseJerseyTest { String documentPdfToken = clientUtil.login("document_pdf"); // Create a document - long create1Date = new Date().getTime(); - JsonObject json = target().path("/document").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, documentPdfToken) - .put(Entity.form(new Form() - .param("title", "My super title document 1") - .param("description", "My super description for document 1") - .param("language", "eng") - .param("create_date", Long.toString(create1Date))), JsonObject.class); - String document1Id = json.getString("id"); - Assert.assertNotNull(document1Id); + String document1Id = clientUtil.createDocument(documentPdfToken); // Add a PDF file - String file1Id = clientUtil.addFileToDocument("file/wikipedia.pdf", "wikipedia.pdf", documentPdfToken, document1Id); + String file1Id = clientUtil.addFileToDocument(FILE_WIKIPEDIA_PDF, documentPdfToken, document1Id); // Search documents by query in full content - json = target().path("/document/list") + JsonObject json = target().path("/document/list") .queryParam("search", "full:vrandecic") .request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, documentPdfToken) @@ -624,22 +597,13 @@ public class TestDocumentResource extends BaseJerseyTest { String documentPlainToken = clientUtil.login("document_plain"); // Create a document - long create1Date = new Date().getTime(); - JsonObject json = target().path("/document").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, documentPlainToken) - .put(Entity.form(new Form() - .param("title", "My super title document 1") - .param("description", "My super description for document 1") - .param("language", "eng") - .param("create_date", Long.toString(create1Date))), JsonObject.class); - String document1Id = json.getString("id"); - Assert.assertNotNull(document1Id); + String document1Id = clientUtil.createDocument(documentPlainToken); // Add a plain text file - String file1Id = clientUtil.addFileToDocument("file/document.txt", "document.txt", documentPlainToken, document1Id); + String file1Id = clientUtil.addFileToDocument(FILE_DOCUMENT_TXT, documentPlainToken, document1Id); // Search documents by query in full content - json = target().path("/document/list") + JsonObject json = target().path("/document/list") .queryParam("search", "full:love") .request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, documentPlainToken) @@ -694,22 +658,13 @@ public class TestDocumentResource extends BaseJerseyTest { String documentVideoToken = clientUtil.login("document_video"); // Create a document - long create1Date = new Date().getTime(); - JsonObject json = target().path("/document").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, documentVideoToken) - .put(Entity.form(new Form() - .param("title", "My super title document 1") - .param("description", "My super description for document 1") - .param("language", "eng") - .param("create_date", Long.toString(create1Date))), JsonObject.class); - String document1Id = json.getString("id"); - Assert.assertNotNull(document1Id); + String document1Id = clientUtil.createDocument(documentVideoToken); // Add a video file - String file1Id = clientUtil.addFileToDocument("file/video.webm", "video.webm", documentVideoToken, document1Id); + String file1Id = clientUtil.addFileToDocument(FILE_VIDEO_WEBM, documentVideoToken, document1Id); // Search documents by query in full content - json = target().path("/document/list") + JsonObject json = target().path("/document/list") .queryParam("search", "full:vp9") .request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, documentVideoToken) @@ -754,22 +709,13 @@ public class TestDocumentResource extends BaseJerseyTest { String documentPptxToken = clientUtil.login("document_pptx"); // Create a document - long create1Date = new Date().getTime(); - JsonObject json = target().path("/document").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, documentPptxToken) - .put(Entity.form(new Form() - .param("title", "My super title document 1") - .param("description", "My super description for document 1") - .param("language", "eng") - .param("create_date", Long.toString(create1Date))), JsonObject.class); - String document1Id = json.getString("id"); - Assert.assertNotNull(document1Id); + String document1Id = clientUtil.createDocument(documentPptxToken); // Add a PPTX file - String file1Id = clientUtil.addFileToDocument("file/apache.pptx", "apache.pptx", documentPptxToken, document1Id); + String file1Id = clientUtil.addFileToDocument(FILE_APACHE_PPTX, documentPptxToken, document1Id); // Search documents by query in full content - json = target().path("/document/list") + JsonObject json = target().path("/document/list") .queryParam("search", "full:scaling") .request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, documentPptxToken) @@ -1043,4 +989,4 @@ public class TestDocumentResource extends BaseJerseyTest { Assert.assertEquals("BOOLEAN", meta.getString("type")); Assert.assertTrue(meta.getBoolean("value")); } -} \ No newline at end of file +} diff --git a/docs-web/src/test/java/com/sismics/docs/rest/TestFileResource.java b/docs-web/src/test/java/com/sismics/docs/rest/TestFileResource.java index b86c9939..ee01b8fd 100644 --- a/docs-web/src/test/java/com/sismics/docs/rest/TestFileResource.java +++ b/docs-web/src/test/java/com/sismics/docs/rest/TestFileResource.java @@ -23,6 +23,7 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.Date; +import java.util.zip.ZipInputStream; /** * Exhaustive test of the file resource. @@ -37,53 +38,18 @@ public class TestFileResource extends BaseJerseyTest { */ @Test public void testFileResource() throws Exception { - // Login file1 - clientUtil.createUser("file1"); - String file1Token = clientUtil.login("file1"); + // Login file_resources + clientUtil.createUser("file_resources"); + String file1Token = clientUtil.login("file_resources"); // Create a document - long create1Date = new Date().getTime(); - JsonObject json = target().path("/document").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file1Token) - .put(Entity.form(new Form() - .param("title", "File test document 1") - .param("language", "eng") - .param("create_date", Long.toString(create1Date))), JsonObject.class); - String document1Id = json.getString("id"); - Assert.assertNotNull(document1Id); + String document1Id = clientUtil.createDocument(file1Token); // Add a file - String file1Id; - try (InputStream is = Resources.getResource("file/PIA00452.jpg").openStream()) { - StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "PIA00452.jpg"); - try (FormDataMultiPart multiPart = new FormDataMultiPart()) { - json = target() - .register(MultiPartFeature.class) - .path("/file").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file1Token) - .put(Entity.entity(multiPart.field("id", document1Id).bodyPart(streamDataBodyPart), - MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class); - file1Id = json.getString("id"); - Assert.assertNotNull(file1Id); - Assert.assertEquals(163510L, json.getJsonNumber("size").longValue()); - } - } + String file1Id = clientUtil.addFileToDocument(FILE_PIA_00452_JPG, file1Token, document1Id); // Add a file - String file2Id; - try (InputStream is = Resources.getResource("file/PIA00452.jpg").openStream()) { - StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "PIA00452.jpg"); - try (FormDataMultiPart multiPart = new FormDataMultiPart()) { - json = target() - .register(MultiPartFeature.class) - .path("/file").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file1Token) - .put(Entity.entity(multiPart.field("id", document1Id).bodyPart(streamDataBodyPart), - MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class); - file2Id = json.getString("id"); - Assert.assertNotNull(file2Id); - } - } + String file2Id = clientUtil.addFileToDocument(FILE_PIA_00452_JPG, file1Token, document1Id); // Get the file data Response response = target().path("/file/" + file1Id + "/data").request() @@ -131,7 +97,7 @@ public class TestFileResource extends BaseJerseyTest { Assert.assertEquals(MimeType.DEFAULT, MimeTypeUtil.guessMimeType(storedFile, null)); // Get all files from a document - json = target().path("/file/list") + JsonObject json = target().path("/file/list") .queryParam("id", document1Id) .request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file1Token) @@ -293,6 +259,66 @@ public class TestFileResource extends BaseJerseyTest { Assert.assertEquals("document.txt", files.getJsonObject(0).getString("name")); Assert.assertEquals(1, files.getJsonObject(0).getInt("version")); } + + @Test + public void testFileResourceZip() throws Exception { + // Login file_resources + clientUtil.createUser("file_resources_zip"); + String file1Token = clientUtil.login("file_resources_zip"); + + // Create a document + String document1Id = clientUtil.createDocument(file1Token); + + // Add a file + String file1Id = clientUtil.addFileToDocument(FILE_PIA_00452_JPG, file1Token, document1Id); + + // Get a ZIP from all files of the document + Response response = target().path("/file/zip") + .queryParam("id", document1Id) + .request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file1Token) + .get(); + Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); + InputStream is = (InputStream) response.getEntity(); + ZipInputStream zipInputStream = new ZipInputStream(is); + Assert.assertEquals(zipInputStream.getNextEntry().getName(), "0-PIA00452.jpg"); + Assert.assertNull(zipInputStream.getNextEntry()); + + // Fail if we don't have access to the document + response = target().path("/file/zip") + .queryParam("id", document1Id) + .request() + .get(); + Assert.assertEquals(Status.NOT_FOUND, Status.fromStatusCode(response.getStatus())); + + // Create a document + String document2Id = clientUtil.createDocument(file1Token); + + // Add a file + String file2Id = clientUtil.addFileToDocument(FILE_EINSTEIN_ROOSEVELT_LETTER_PNG, file1Token, document2Id); + + // Get a ZIP from both files + response = target().path("/file/zip") + .request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file1Token) + .post(Entity.form(new Form() + .param("files", file1Id) + .param("files", file2Id))); + Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); + is = (InputStream) response.getEntity(); + zipInputStream = new ZipInputStream(is); + Assert.assertNotNull(zipInputStream.getNextEntry().getName()); + Assert.assertNotNull(zipInputStream.getNextEntry().getName()); + Assert.assertNull(zipInputStream.getNextEntry()); + + // Fail if we don't have access to the files + response = target().path("/file/zip") + .request() + .post(Entity.form(new Form() + .param("files", file1Id) + .param("files", file2Id))); + Assert.assertEquals(Status.FORBIDDEN, Status.fromStatusCode(response.getStatus())); + } /** * Test using a ZIP file. @@ -300,38 +326,16 @@ public class TestFileResource extends BaseJerseyTest { * @throws Exception e */ @Test - public void testZipFile() throws Exception { - // Login file1 - clientUtil.createUser("file2"); - String file2Token = clientUtil.login("file2"); + public void testZipFileUpload() throws Exception { + // Login file_zip + clientUtil.createUser("file_zip"); + String fileZipToken = clientUtil.login("file_zip"); // Create a document - long create1Date = new Date().getTime(); - JsonObject json = target().path("/document").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file2Token) - .put(Entity.form(new Form() - .param("title", "File test document 1") - .param("language", "eng") - .param("create_date", Long.toString(create1Date))), JsonObject.class); - String document1Id = json.getString("id"); - Assert.assertNotNull(document1Id); + String document1Id = clientUtil.createDocument(fileZipToken); // Add a file - String file1Id; - try (InputStream is = Resources.getResource("file/wikipedia.zip").openStream()) { - StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "wikipedia.zip"); - try (FormDataMultiPart multiPart = new FormDataMultiPart()) { - json = target() - .register(MultiPartFeature.class) - .path("/file").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file2Token) - .put(Entity.entity(multiPart.field("id", document1Id).bodyPart(streamDataBodyPart), - MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class); - file1Id = json.getString("id"); - Assert.assertNotNull(file1Id); - Assert.assertEquals(525069L, json.getJsonNumber("size").longValue()); - } - } + clientUtil.addFileToDocument(FILE_WIKIPEDIA_ZIP, fileZipToken, document1Id); } /** @@ -341,29 +345,16 @@ public class TestFileResource extends BaseJerseyTest { */ @Test public void testOrphanFile() throws Exception { - // Login file3 - clientUtil.createUser("file3"); - String file3Token = clientUtil.login("file3"); + // Login file_orphan + clientUtil.createUser("file_orphan"); + String fileOrphanToken = clientUtil.login("file_orphan"); // Add a file - String file1Id; - try (InputStream is = Resources.getResource("file/PIA00452.jpg").openStream()) { - StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "PIA00452.jpg"); - try (FormDataMultiPart multiPart = new FormDataMultiPart()) { - JsonObject json = target() - .register(MultiPartFeature.class) - .path("/file").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file3Token) - .put(Entity.entity(multiPart.bodyPart(streamDataBodyPart), - MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class); - file1Id = json.getString("id"); - Assert.assertNotNull(file1Id); - } - } + String file1Id = clientUtil.addFileToDocument(FILE_PIA_00452_JPG, fileOrphanToken, null); // Get all orphan files JsonObject json = target().path("/file/list").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file3Token) + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileOrphanToken) .get(JsonObject.class); JsonArray files = json.getJsonArray("files"); Assert.assertEquals(1, files.size()); @@ -372,7 +363,7 @@ public class TestFileResource extends BaseJerseyTest { Response response = target().path("/file/" + file1Id + "/data") .queryParam("size", "thumb") .request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file3Token) + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileOrphanToken) .get(); Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); InputStream is = (InputStream) response.getEntity(); @@ -382,56 +373,37 @@ public class TestFileResource extends BaseJerseyTest { // Get the file data response = target().path("/file/" + file1Id + "/data").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file3Token) + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileOrphanToken) .get(); is = (InputStream) response.getEntity(); fileBytes = ByteStreams.toByteArray(is); Assert.assertEquals(MimeType.IMAGE_JPEG, MimeTypeUtil.guessMimeType(fileBytes, null)); Assert.assertEquals(163510, fileBytes.length); - // Create a document - json = target().path("/document").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file3Token) - .put(Entity.form(new Form() - .param("title", "File test document 1") - .param("language", "eng")), JsonObject.class); - String document1Id = json.getString("id"); - Assert.assertNotNull(document1Id); + // Create another document + String document2Id = clientUtil.createDocument(fileOrphanToken); // Attach a file to a document target().path("/file/" + file1Id + "/attach").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file3Token) + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileOrphanToken) .post(Entity.form(new Form() - .param("id", document1Id)), JsonObject.class); + .param("id", document2Id)), JsonObject.class); // Get all files from a document json = target().path("/file/list") - .queryParam("id", document1Id) + .queryParam("id", document2Id) .request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file3Token) + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileOrphanToken) .get(JsonObject.class); files = json.getJsonArray("files"); Assert.assertEquals(1, files.size()); // Add a file - String file2Id; - try (InputStream is0 = Resources.getResource("file/PIA00452.jpg").openStream()) { - StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is0, "PIA00452.jpg"); - try (FormDataMultiPart multiPart = new FormDataMultiPart()) { - json = target() - .register(MultiPartFeature.class) - .path("/file").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file3Token) - .put(Entity.entity(multiPart.bodyPart(streamDataBodyPart), - MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class); - file2Id = json.getString("id"); - Assert.assertNotNull(file2Id); - } - } + String file2Id = clientUtil.addFileToDocument(FILE_PIA_00452_JPG, fileOrphanToken, null); // Deletes a file json = target().path("/file/" + file2Id).request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, file3Token) + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileOrphanToken) .delete(JsonObject.class); Assert.assertEquals("ok", json.getString("status")); } @@ -448,21 +420,8 @@ public class TestFileResource extends BaseJerseyTest { String fileQuotaToken = clientUtil.login("file_quota"); // Add a file (292641 bytes large) - String file1Id; - try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) { - StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "Einstein-Roosevelt-letter.png"); - try (FormDataMultiPart multiPart = new FormDataMultiPart()) { - JsonObject json = target() - .register(MultiPartFeature.class) - .path("/file").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaToken) - .put(Entity.entity(multiPart.bodyPart(streamDataBodyPart), - MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class); - file1Id = json.getString("id"); - Assert.assertNotNull(file1Id); - } - } - + String file1Id = clientUtil.addFileToDocument(FILE_EINSTEIN_ROOSEVELT_LETTER_PNG, fileQuotaToken, null); + // Check current quota JsonObject json = target().path("/user").request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaToken) @@ -470,17 +429,7 @@ public class TestFileResource extends BaseJerseyTest { Assert.assertEquals(292641L, json.getJsonNumber("storage_current").longValue()); // Add a file (292641 bytes large) - try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) { - StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "Einstein-Roosevelt-letter.png"); - try (FormDataMultiPart multiPart = new FormDataMultiPart()) { - target() - .register(MultiPartFeature.class) - .path("/file").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaToken) - .put(Entity.entity(multiPart.bodyPart(streamDataBodyPart), - MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class); - } - } + clientUtil.addFileToDocument(FILE_EINSTEIN_ROOSEVELT_LETTER_PNG, fileQuotaToken, null); // Check current quota json = target().path("/user").request() @@ -489,17 +438,7 @@ public class TestFileResource extends BaseJerseyTest { Assert.assertEquals(585282L, json.getJsonNumber("storage_current").longValue()); // Add a file (292641 bytes large) - try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) { - StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "Einstein-Roosevelt-letter.png"); - try (FormDataMultiPart multiPart = new FormDataMultiPart()) { - target() - .register(MultiPartFeature.class) - .path("/file").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaToken) - .put(Entity.entity(multiPart.bodyPart(streamDataBodyPart), - MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class); - } - } + clientUtil.addFileToDocument(FILE_EINSTEIN_ROOSEVELT_LETTER_PNG, fileQuotaToken, null); // Check current quota json = target().path("/user").request() @@ -508,17 +447,10 @@ public class TestFileResource extends BaseJerseyTest { Assert.assertEquals(877923L, json.getJsonNumber("storage_current").longValue()); // Add a file (292641 bytes large) - try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) { - StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "Einstein-Roosevelt-letter.png"); - try (FormDataMultiPart multiPart = new FormDataMultiPart()) { - Response response = target() - .register(MultiPartFeature.class) - .path("/file").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaToken) - .put(Entity.entity(multiPart.bodyPart(streamDataBodyPart), - MediaType.MULTIPART_FORM_DATA_TYPE)); - Assert.assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus()); - } + try { + clientUtil.addFileToDocument(FILE_EINSTEIN_ROOSEVELT_LETTER_PNG, fileQuotaToken, null); + Assert.fail(); + } catch (javax.ws.rs.BadRequestException ignored) { } // Deletes a file @@ -545,17 +477,7 @@ public class TestFileResource extends BaseJerseyTest { Assert.assertNotNull(document1Id); // Add a file to this document (163510 bytes large) - try (InputStream is = Resources.getResource("file/PIA00452.jpg").openStream()) { - StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "PIA00452.jpg"); - try (FormDataMultiPart multiPart = new FormDataMultiPart()) { - target() - .register(MultiPartFeature.class) - .path("/file").request() - .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaToken) - .put(Entity.entity(multiPart.field("id", document1Id).bodyPart(streamDataBodyPart), - MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class); - } - } + clientUtil.addFileToDocument(FILE_PIA_00452_JPG, fileQuotaToken, document1Id); // Check current quota json = target().path("/user").request() @@ -575,4 +497,4 @@ public class TestFileResource extends BaseJerseyTest { .get(JsonObject.class); Assert.assertEquals(585282L, json.getJsonNumber("storage_current").longValue()); } -} \ No newline at end of file +}