From 4cb5b7fdbbc2bcd80d743ea5612a8bb5cad762d8 Mon Sep 17 00:00:00 2001 From: jendib Date: Wed, 14 Aug 2013 00:47:58 +0200 Subject: [PATCH] File sharing (server done) --- .../sismics/docs/core/dao/jpa/FileDao.java | 6 ++ .../docs/core/dao/jpa/FileShareDao.java | 6 +- docs-parent/TODO | 3 +- .../docs/rest/resource/FileResource.java | 83 ++++++++++++++----- .../docs/rest/TestFileShareResource.java | 22 +++++ 5 files changed, 95 insertions(+), 25 deletions(-) diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/FileDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/FileDao.java index 74b3a57a..162c258a 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/FileDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/FileDao.java @@ -64,6 +64,12 @@ public class FileDao { // Delete the file Date dateNow = new Date(); fileDb.setDeleteDate(dateNow); + + // Delete linked data + q = em.createQuery("update FileShare fs set fs.deleteDate = :dateNow where fs.fileId = :fileId and fs.deleteDate is null"); + q.setParameter("fileId", id); + q.setParameter("dateNow", dateNow); + q.executeUpdate(); } /** diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/FileShareDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/FileShareDao.java index 8ac9f3b0..1bea51c2 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/FileShareDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/FileShareDao.java @@ -46,7 +46,11 @@ public class FileShareDao { EntityManager em = ThreadLocalContext.get().getEntityManager(); Query q = em.createQuery("select fs from FileShare fs where fs.id = :id and fs.deleteDate is null"); q.setParameter("id", id); - return (FileShare) q.getSingleResult(); + try { + return (FileShare) q.getSingleResult(); + } catch (NoResultException e) { + return null; + } } /** diff --git a/docs-parent/TODO b/docs-parent/TODO index f7de6e54..ec52e2e6 100644 --- a/docs-parent/TODO +++ b/docs-parent/TODO @@ -1 +1,2 @@ -- Share a file with a link (for a limited time) \ No newline at end of file +- Share a file with a link (client) +- Add a label to a file share \ No newline at end of file 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 3546ea3a..6c496711 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 @@ -1,9 +1,37 @@ package com.sismics.docs.rest.resource; +import java.io.BufferedInputStream; +import java.io.InputStream; +import java.nio.file.Paths; +import java.text.MessageFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.persistence.NoResultException; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; + import com.sismics.docs.core.dao.jpa.DocumentDao; import com.sismics.docs.core.dao.jpa.FileDao; +import com.sismics.docs.core.dao.jpa.FileShareDao; import com.sismics.docs.core.model.jpa.Document; import com.sismics.docs.core.model.jpa.File; +import com.sismics.docs.core.model.jpa.FileShare; import com.sismics.docs.core.util.DirectoryUtil; import com.sismics.rest.exception.ClientException; import com.sismics.rest.exception.ForbiddenClientException; @@ -14,21 +42,6 @@ import com.sismics.util.ImageUtil; import com.sismics.util.mime.MimeTypeUtil; import com.sun.jersey.multipart.FormDataBodyPart; import com.sun.jersey.multipart.FormDataParam; -import org.codehaus.jettison.json.JSONException; -import org.codehaus.jettison.json.JSONObject; - -import javax.persistence.NoResultException; -import javax.ws.rs.*; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.io.BufferedInputStream; -import java.io.InputStream; -import java.nio.file.Paths; -import java.text.MessageFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; /** * File REST resources. @@ -54,6 +67,7 @@ public class FileResource extends BaseResource { } FileDao fileDao = new FileDao(); + FileShareDao fileShareDao = new FileShareDao(); DocumentDao documentDao = new DocumentDao(); File fileDb; try { @@ -69,6 +83,16 @@ public class FileResource extends BaseResource { file.put("document_id", fileDb.getDocumentId()); file.put("create_date", fileDb.getCreateDate().getTime()); + // Add file shares + List fileShareDbList = fileShareDao.getByFileId(id); + List fileShareList = new ArrayList<>(); + for (FileShare fileShareDb : fileShareDbList) { + JSONObject fileShare = new JSONObject(); + fileShare.put("id", fileShareDb.getId()); + fileShareList.add(fileShare); + } + file.put("shares", fileShareList); + return Response.ok().entity(file).build(); } @@ -264,7 +288,7 @@ public class FileResource extends BaseResource { /** * Returns a file. * - * @param id File ID + * @param fileId File ID * @return Response * @throws JSONException */ @@ -272,9 +296,20 @@ public class FileResource extends BaseResource { @Path("{id: [a-z0-9\\-]+}/data") @Produces(MediaType.APPLICATION_OCTET_STREAM) public Response data( - @PathParam("id") final String id, + @PathParam("id") final String fileId, + @QueryParam("share") String fileShareId, @QueryParam("thumbnail") boolean thumbnail) throws JSONException { - if (!authenticate()) { + // Handle file sharing + FileShareDao fileShareDao = new FileShareDao(); + if (fileShareId != null) { + FileShare fileShare = fileShareDao.getFileShare(fileShareId); + if (fileShare == null) { + throw new ClientException("FileShareNotFound", "File share not found"); + } + if (!fileShare.getFileId().equals(fileId)) { + throw new ClientException("InvalidFile", "This file share is not linked to this file"); + } + } else if (!authenticate()) { throw new ForbiddenClientException(); } @@ -283,10 +318,12 @@ public class FileResource extends BaseResource { DocumentDao documentDao = new DocumentDao(); File file; try { - file = fileDao.getFile(id); - documentDao.getDocument(file.getDocumentId(), principal.getId()); + file = fileDao.getFile(fileId); + if (fileShareId == null) { + documentDao.getDocument(file.getDocumentId(), principal.getId()); + } } catch (NoResultException e) { - throw new ClientException("FileNotFound", MessageFormat.format("File not found: {0}", id)); + throw new ClientException("FileNotFound", MessageFormat.format("File not found: {0}", fileId)); } @@ -294,12 +331,12 @@ public class FileResource extends BaseResource { java.io.File storedfile; if (thumbnail) { if (ImageUtil.isImage(file.getMimeType())) { - storedfile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), id + "_thumb").toFile(); + storedfile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), fileId + "_thumb").toFile(); } else { storedfile = new java.io.File(getClass().getResource("/image/file.png").getFile()); } } else { - storedfile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), id).toFile(); + storedfile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), fileId).toFile(); } return Response.ok(storedfile) diff --git a/docs-web/src/test/java/com/sismics/docs/rest/TestFileShareResource.java b/docs-web/src/test/java/com/sismics/docs/rest/TestFileShareResource.java index 28084760..2864bb40 100644 --- a/docs-web/src/test/java/com/sismics/docs/rest/TestFileShareResource.java +++ b/docs-web/src/test/java/com/sismics/docs/rest/TestFileShareResource.java @@ -10,6 +10,7 @@ import junit.framework.Assert; import org.codehaus.jettison.json.JSONObject; import org.junit.Test; +import com.google.common.io.ByteStreams; import com.sismics.docs.rest.filter.CookieAuthenticationFilter; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.ClientResponse.Status; @@ -71,6 +72,27 @@ public class TestFileShareResource extends BaseJerseyTest { json = response.getEntity(JSONObject.class); String fileShare1Id = json.getString("id"); + // Get the file data anonymously + fileResource = resource().path("/file/" + file1Id + "/data"); + MultivaluedMapImpl getParams = new MultivaluedMapImpl(); + getParams.putSingle("thumbnail", false); + getParams.putSingle("share", fileShare1Id); + response = fileResource.queryParams(getParams).get(ClientResponse.class); + Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); + InputStream is = response.getEntityInputStream(); + byte[] fileBytes = ByteStreams.toByteArray(is); + Assert.assertEquals(163510, fileBytes.length); + + // Get the file + fileResource = resource().path("/file/" + file1Id); + fileResource.addFilter(new CookieAuthenticationFilter(fileShare1AuthenticationToken)); + response = fileResource.get(ClientResponse.class); + json = response.getEntity(JSONObject.class); + Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); + Assert.assertEquals(file1Id, json.getString("id")); + Assert.assertEquals(1, json.getJSONArray("shares").length()); + Assert.assertEquals(fileShare1Id, json.getJSONArray("shares").getJSONObject(0).getString("id")); + // Deletes the share fileShareResource = resource().path("/fileshare/" + fileShare1Id); fileShareResource.addFilter(new CookieAuthenticationFilter(fileShare1AuthenticationToken));