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 4287d2c2..049a2bb8 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 @@ -91,7 +91,7 @@ public class FileDao { @SuppressWarnings("unchecked") public List getByDocumentId(String documentId) { EntityManager em = ThreadLocalContext.get().getEntityManager(); - Query q = em.createQuery("select f from File f where f.documentId = :documentId and f.deleteDate is null"); + Query q = em.createQuery("select f from File f where f.documentId = :documentId and f.deleteDate is null order by f.order asc"); q.setParameter("documentId", documentId); return q.getResultList(); } diff --git a/docs-core/src/main/java/com/sismics/docs/core/model/jpa/File.java b/docs-core/src/main/java/com/sismics/docs/core/model/jpa/File.java index 063bb0fd..08ad65d6 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/model/jpa/File.java +++ b/docs-core/src/main/java/com/sismics/docs/core/model/jpa/File.java @@ -48,6 +48,12 @@ public class File { @Column(name = "FIL_DELETEDATE_D") private Date deleteDate; + /** + * Display order of this file. + */ + @Column(name = "FIL_ORDER_N") + private Integer order; + /** * Getter of id. * @@ -137,6 +143,24 @@ public class File { public void setDeleteDate(Date deleteDate) { this.deleteDate = deleteDate; } + + /** + * Getter of order. + * + * @return the order + */ + public Integer getOrder() { + return order; + } + + /** + * Setter of order. + * + * @param order order + */ + public void setOrder(Integer order) { + this.order = order; + } @Override public String toString() { diff --git a/docs-core/src/main/resources/config.properties b/docs-core/src/main/resources/config.properties index c0e441b7..9484a82d 100644 --- a/docs-core/src/main/resources/config.properties +++ b/docs-core/src/main/resources/config.properties @@ -1 +1 @@ -db.version=0 \ No newline at end of file +db.version=1 \ No newline at end of file diff --git a/docs-core/src/main/resources/db/update/dbupdate-001-0.sql b/docs-core/src/main/resources/db/update/dbupdate-001-0.sql new file mode 100644 index 00000000..400b1628 --- /dev/null +++ b/docs-core/src/main/resources/db/update/dbupdate-001-0.sql @@ -0,0 +1,2 @@ +alter table T_FILE add column FIL_ORDER_N int; +update T_CONFIG set CFG_VALUE_C='1' where CFG_ID_C='DB_VERSION'; diff --git a/docs-parent/TODO b/docs-parent/TODO index 7f44b95f..a202029a 100644 --- a/docs-parent/TODO +++ b/docs-parent/TODO @@ -1,4 +1,3 @@ - Display logs (client) -- Reordering files and add new files to the end (server) - Tag stats (client/server) - Users administration (client) \ 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 e5ea0f5b..5c3d7401 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 @@ -12,7 +12,9 @@ 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; @@ -125,8 +127,15 @@ public class FileResource extends BaseResource { } try { + // Get files of this document + int order = 0; + for (File file : fileDao.getByDocumentId(documentId)) { + file.setOrder(order++); + } + // Create the file File file = new File(); + file.setOrder(order); file.setDocumentId(document.getId()); file.setMimeType(mimeType); String fileId = fileDao.create(file); @@ -144,6 +153,43 @@ public class FileResource extends BaseResource { } } + /** + * Reorder files. + * + * @param id Document ID + * @param order List of files ID in the new order + * @return Response + * @throws JSONException + */ + @POST + @Path("reorder") + @Produces(MediaType.APPLICATION_JSON) + public Response reorder( + @FormParam("id") String documentId, + @FormParam("order") List idList) throws JSONException { + if (!authenticate()) { + throw new ForbiddenClientException(); + } + + // Validate input data + ValidationUtil.validateRequired(documentId, "id"); + ValidationUtil.validateRequired(idList, "order"); + + // Reorder files + FileDao fileDao = new FileDao(); + for (File file : fileDao.getByDocumentId(documentId)) { + int order = idList.lastIndexOf(file.getId()); + if (order != -1) { + file.setOrder(order); + } + } + + // Always return ok + JSONObject response = new JSONObject(); + response.put("status", "ok"); + return Response.ok().entity(response).build(); + } + /** * Returns files linked to a document. * diff --git a/docs-web/src/main/webapp/js/controller/DocumentView.js b/docs-web/src/main/webapp/js/controller/DocumentView.js index 02d3c56b..1b197ed1 100644 --- a/docs-web/src/main/webapp/js/controller/DocumentView.js +++ b/docs-web/src/main/webapp/js/controller/DocumentView.js @@ -15,8 +15,14 @@ App.controller('DocumentView', function($scope, $state, $stateParams, $dialog, R forcePlaceholderSize: true, tolerance: 'pointer', handle: '.handle', - update: function(event, ui) { - // TODO Send new positions to server + stop: function(e, ui) { + // Send new positions to server + $scope.$apply(function() { + Restangular.one('file').post('reorder', { + id: $stateParams.id, + order: _.pluck($scope.files, 'id') + }); + }); } }; 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 604484c4..7d98b15b 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 @@ -64,6 +64,21 @@ public class TestFileResource extends BaseJerseyTest { json = response.getEntity(JSONObject.class); String file1Id = json.getString("id"); + // Add a file + fileResource = resource().path("/file"); + fileResource.addFilter(new CookieAuthenticationFilter(file1AuthenticationToken)); + form = new FormDataMultiPart(); + file = this.getClass().getResourceAsStream("/file/PIA00452.jpg"); + fdp = new FormDataBodyPart("file", + new BufferedInputStream(file), + MediaType.APPLICATION_OCTET_STREAM_TYPE); + form.bodyPart(fdp); + form.field("id", document1Id); + response = fileResource.type(MediaType.MULTIPART_FORM_DATA).put(ClientResponse.class, form); + Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); + json = response.getEntity(JSONObject.class); + String file2Id = json.getString("id"); + // Get the file fileResource = resource().path("/file/" + file1Id); fileResource.addFilter(new CookieAuthenticationFilter(file1AuthenticationToken)); @@ -104,7 +119,32 @@ public class TestFileResource extends BaseJerseyTest { json = response.getEntity(JSONObject.class); Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); JSONArray files = json.getJSONArray("files"); - Assert.assertEquals(1, files.length()); + Assert.assertEquals(2, files.length()); + Assert.assertEquals(file1Id, files.getJSONObject(0).getString("id")); + Assert.assertEquals(file2Id, files.getJSONObject(1).getString("id")); + + // Reorder files + fileResource = resource().path("/file/reorder"); + fileResource.addFilter(new CookieAuthenticationFilter(file1AuthenticationToken)); + postParams = new MultivaluedMapImpl(); + postParams.add("id", document1Id); + postParams.add("order", file2Id); + postParams.add("order", file1Id); + response = fileResource.post(ClientResponse.class, postParams); + Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); + + // Get all files from a document + fileResource = resource().path("/file/list"); + fileResource.addFilter(new CookieAuthenticationFilter(file1AuthenticationToken)); + getParams = new MultivaluedMapImpl(); + getParams.putSingle("id", document1Id); + response = fileResource.queryParams(getParams).get(ClientResponse.class); + json = response.getEntity(JSONObject.class); + Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); + files = json.getJSONArray("files"); + Assert.assertEquals(2, files.length()); + Assert.assertEquals(file2Id, files.getJSONObject(0).getString("id")); + Assert.assertEquals(file1Id, files.getJSONObject(1).getString("id")); // Deletes a file documentResource = resource().path("/file/" + file1Id); @@ -123,6 +163,6 @@ public class TestFileResource extends BaseJerseyTest { json = response.getEntity(JSONObject.class); Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); files = json.getJSONArray("files"); - Assert.assertEquals(0, files.length()); + Assert.assertEquals(1, files.length()); } } \ No newline at end of file