diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java index 2538b2e9..f721824e 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java @@ -184,6 +184,11 @@ public class DocumentDao { q.setParameter("dateNow", dateNow); q.executeUpdate(); + q = em.createQuery("update Relation r set r.deleteDate = :dateNow where (r.fromDocumentId = :documentId or r.toDocumentId = :documentId) and r.deleteDate is not null"); + q.setParameter("documentId", id); + q.setParameter("dateNow", dateNow); + q.executeUpdate(); + // Create audit log AuditLogUtil.create(documentDb, AuditLogType.DELETE, userId); } diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/RelationDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/RelationDao.java new file mode 100644 index 00000000..ea483c53 --- /dev/null +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/RelationDao.java @@ -0,0 +1,97 @@ +package com.sismics.docs.core.dao.jpa; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import javax.persistence.EntityManager; +import javax.persistence.Query; + +import com.sismics.docs.core.dao.jpa.dto.RelationDto; +import com.sismics.docs.core.model.jpa.Relation; +import com.sismics.util.context.ThreadLocalContext; + +/** + * Relation DAO. + * + * @author bgamard + */ +public class RelationDao { + /** + * Get all relations from/to a document. + * + * @param documentId Document ID + * @return List of relations + */ + @SuppressWarnings("unchecked") + public List getByDocumentId(String documentId) { + EntityManager em = ThreadLocalContext.get().getEntityManager(); + StringBuilder sb = new StringBuilder("select d.DOC_ID_C, d.DOC_TITLE_C "); + sb.append(" from T_RELATION r "); + sb.append(" join T_DOCUMENT d on d.DOC_ID_C = r.REL_IDDOCFROM_C and r.REL_IDDOCFROM_C != :documentId or d.DOC_ID_C = r.REL_IDDOCTO_C and r.REL_IDDOCTO_C != :documentId "); + sb.append(" where (r.REL_IDDOCFROM_C = :documentId or r.REL_IDDOCTO_C = :documentId) "); + sb.append(" and r.REL_DELETEDATE_D is null "); + sb.append(" order by d.DOC_TITLE_C "); + + // Perform the query + Query q = em.createNativeQuery(sb.toString()); + q.setParameter("documentId", documentId); + List l = q.getResultList(); + + // Assemble results + List relationDtoList = new ArrayList(); + for (Object[] o : l) { + int i = 0; + RelationDto relationDto = new RelationDto(); + relationDto.setId((String) o[i++]); + relationDto.setTitle((String) o[i++]); + relationDtoList.add(relationDto); + } + return relationDtoList; + } + + /** + * Update relations on a document. + * + * @param documentId Document ID + * @param documentIdSet Set of document ID + */ + public void updateRelationList(String documentId, Set documentIdSet) { + EntityManager em = ThreadLocalContext.get().getEntityManager(); + + // Get current relations from this document + Query q = em.createQuery("select r from Relation r where r.fromDocumentId = :documentId and r.deleteDate is null"); + q.setParameter("documentId", documentId); + @SuppressWarnings("unchecked") + List relationList = q.getResultList(); + + // Deleting relations no longer there + for (Relation relation : relationList) { + if (!documentIdSet.contains(relation.getToDocumentId())) { + relation.setDeleteDate(new Date()); + } + } + + // Adding new relations + for (String targetDocId : documentIdSet) { + boolean found = false; + for (Relation relation : relationList) { + if (relation.getToDocumentId().equals(targetDocId)) { + found = true; + break; + } + } + + if (!found) { + Relation relation = new Relation(); + relation.setId(UUID.randomUUID().toString()); + relation.setFromDocumentId(documentId); + relation.setToDocumentId(targetDocId); + em.persist(relation); + } + } + } +} + diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/RelationDto.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/RelationDto.java new file mode 100644 index 00000000..c44e4ec9 --- /dev/null +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/RelationDto.java @@ -0,0 +1,34 @@ +package com.sismics.docs.core.dao.jpa.dto; + +/** + * Tag DTO. + * + * @author bgamard + */ +public class RelationDto { + /** + * Document ID. + */ + private String id; + + /** + * Document title. + */ + private String title; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } +} diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/TagDto.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/TagDto.java index c4f38506..81bea5a1 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/TagDto.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/TagDto.java @@ -26,74 +26,34 @@ public class TagDto { */ private String parentId; - /** - * Getter of id. - * - * @return the id - */ public String getId() { return id; } - /** - * Setter of id. - * - * @param id id - */ public void setId(String id) { this.id = id; } - /** - * Getter of name. - * - * @return the name - */ public String getName() { return name; } - /** - * Setter of name. - * - * @param name name - */ public void setName(String name) { this.name = name; } - /** - * Getter of color. - * - * @return the color - */ public String getColor() { return color; } - /** - * Setter of color. - * - * @param color color - */ public void setColor(String color) { this.color = color; } - /** - * Getter of parentId. - * - * @return the parentId - */ public String getParentId() { return parentId; } - /** - * Setter of parentId. - * - * @param color parentId - */ public void setParentId(String parentId) { this.parentId = parentId; } diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java index 1559c504..09be3262 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java @@ -43,12 +43,14 @@ import com.sismics.docs.core.dao.jpa.AclDao; import com.sismics.docs.core.dao.jpa.ContributorDao; import com.sismics.docs.core.dao.jpa.DocumentDao; import com.sismics.docs.core.dao.jpa.FileDao; +import com.sismics.docs.core.dao.jpa.RelationDao; import com.sismics.docs.core.dao.jpa.TagDao; import com.sismics.docs.core.dao.jpa.UserDao; import com.sismics.docs.core.dao.jpa.criteria.DocumentCriteria; import com.sismics.docs.core.dao.jpa.dto.AclDto; import com.sismics.docs.core.dao.jpa.dto.ContributorDto; import com.sismics.docs.core.dao.jpa.dto.DocumentDto; +import com.sismics.docs.core.dao.jpa.dto.RelationDto; import com.sismics.docs.core.dao.jpa.dto.TagDto; import com.sismics.docs.core.event.DocumentCreatedAsyncEvent; import com.sismics.docs.core.event.DocumentDeletedAsyncEvent; @@ -172,6 +174,17 @@ public class DocumentResource extends BaseResource { } document.add("contributors", contributorList); + // Add relations + RelationDao relationDao = new RelationDao(); + List relationDtoList = relationDao.getByDocumentId(documentId); + JsonArrayBuilder relationList = Json.createArrayBuilder(); + for (RelationDto relationDto : relationDtoList) { + relationList.add(Json.createObjectBuilder() + .add("id", relationDto.getId()) + .add("title", relationDto.getTitle())); + } + document.add("relations", relationList); + return Response.ok().entity(document.build()).build(); } @@ -430,6 +443,7 @@ public class DocumentResource extends BaseResource { @FormParam("coverage") String coverage, @FormParam("rights") String rights, @FormParam("tags") List tagList, + @FormParam("relations") List relationList, @FormParam("language") String language, @FormParam("create_date") String createDateStr) { if (!authenticate()) { @@ -493,6 +507,9 @@ public class DocumentResource extends BaseResource { // Update tags updateTagList(documentId, tagList); + // Update relations + updateRelationList(documentId, relationList); + // Raise a document created event DocumentCreatedAsyncEvent documentCreatedAsyncEvent = new DocumentCreatedAsyncEvent(); documentCreatedAsyncEvent.setUserId(principal.getId()); @@ -526,6 +543,7 @@ public class DocumentResource extends BaseResource { @FormParam("coverage") String coverage, @FormParam("rights") String rights, @FormParam("tags") List tagList, + @FormParam("relations") List relationList, @FormParam("language") String language, @FormParam("create_date") String createDateStr) { if (!authenticate()) { @@ -600,6 +618,9 @@ public class DocumentResource extends BaseResource { // Update tags updateTagList(id, tagList); + // Update relations + updateRelationList(id, relationList); + // Raise a document updated event DocumentUpdatedAsyncEvent documentUpdatedAsyncEvent = new DocumentUpdatedAsyncEvent(); documentUpdatedAsyncEvent.setUserId(principal.getId()); @@ -636,6 +657,27 @@ public class DocumentResource extends BaseResource { } } + /** + * Update relations list on a document. + * + * @param documentId Document ID + * @param relationList Relation ID list + */ + private void updateRelationList(String documentId, List relationList) { + if (relationList != null) { + DocumentDao documentDao = new DocumentDao(); + RelationDao relationDao = new RelationDao(); + Set documentIdSet = new HashSet<>(); + for (String targetDocId : relationList) { + Document document = documentDao.getDocument(targetDocId, PermType.READ, principal.getId()); + if (document != null && !documentId.equals(targetDocId)) { + documentIdSet.add(targetDocId); + } + } + relationDao.updateRelationList(documentId, documentIdSet); + } + } + /** * Deletes a document. * 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 2bc19d0a..5551c87a 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 @@ -76,6 +76,16 @@ public class TestDocumentResource extends BaseJerseyTest { String document1Id = json.getString("id"); Assert.assertNotNull(document1Id); + // Create a document with document1 + json = target().path("/document").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token) + .put(Entity.form(new Form() + .param("title", "My super title document 2") + .param("language", "eng") + .param("relations", document1Id)), JsonObject.class); + String document2Id = json.getString("id"); + Assert.assertNotNull(document2Id); + // Add a file String file1Id = null; try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) { @@ -100,13 +110,13 @@ public class TestDocumentResource extends BaseJerseyTest { // List all documents json = target().path("/document/list") .queryParam("sort_column", 3) - .queryParam("asc", false) + .queryParam("asc", true) .request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token) .get(JsonObject.class); JsonArray documents = json.getJsonArray("documents"); JsonArray tags = documents.getJsonObject(0).getJsonArray("tags"); - Assert.assertTrue(documents.size() == 1); + Assert.assertTrue(documents.size() == 2); Assert.assertEquals(document1Id, documents.getJsonObject(0).getString("id")); Assert.assertEquals("eng", documents.getJsonObject(0).getString("language")); Assert.assertEquals(1, documents.getJsonObject(0).getInt("file_count")); @@ -130,8 +140,8 @@ public class TestDocumentResource extends BaseJerseyTest { json = target().path("/document").request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document3Token) .put(Entity.form(new Form() - .param("title", "My super title document 1") - .param("description", "My super description for document 1") + .param("title", "My super title document 3") + .param("description", "My super description for document 3") .param("language", "eng") .param("create_date", Long.toString(create3Date))), JsonObject.class); String document3Id = json.getString("id"); @@ -165,8 +175,8 @@ public class TestDocumentResource extends BaseJerseyTest { // Search documents Assert.assertEquals(1, searchDocuments("full:uranium full:einstein", document1Token)); - Assert.assertEquals(1, searchDocuments("full:title", document1Token)); - Assert.assertEquals(1, searchDocuments("title", document1Token)); + Assert.assertEquals(2, searchDocuments("full:title", document1Token)); + Assert.assertEquals(2, searchDocuments("title", document1Token)); Assert.assertEquals(1, searchDocuments("super description", document1Token)); Assert.assertEquals(1, searchDocuments("subject", document1Token)); Assert.assertEquals(1, searchDocuments("identifier", document1Token)); @@ -177,15 +187,15 @@ public class TestDocumentResource extends BaseJerseyTest { Assert.assertEquals(1, searchDocuments("greenland", document1Token)); Assert.assertEquals(1, searchDocuments("public domain", document1Token)); Assert.assertEquals(0, searchDocuments("by:document3", document1Token)); - Assert.assertEquals(1, searchDocuments("by:document1", document1Token)); + Assert.assertEquals(2, searchDocuments("by:document1", document1Token)); Assert.assertEquals(0, searchDocuments("by:nobody", document1Token)); - Assert.assertEquals(1, searchDocuments("at:" + DateTimeFormat.forPattern("yyyy").print(new Date().getTime()), document1Token)); - Assert.assertEquals(1, searchDocuments("at:" + DateTimeFormat.forPattern("yyyy-MM").print(new Date().getTime()), document1Token)); - Assert.assertEquals(1, searchDocuments("at:" + DateTimeFormat.forPattern("yyyy-MM-dd").print(new Date().getTime()), document1Token)); - Assert.assertEquals(1, searchDocuments("after:2010 before:2040-08", document1Token)); + Assert.assertEquals(2, searchDocuments("at:" + DateTimeFormat.forPattern("yyyy").print(new Date().getTime()), document1Token)); + Assert.assertEquals(2, searchDocuments("at:" + DateTimeFormat.forPattern("yyyy-MM").print(new Date().getTime()), document1Token)); + Assert.assertEquals(2, searchDocuments("at:" + DateTimeFormat.forPattern("yyyy-MM-dd").print(new Date().getTime()), document1Token)); + Assert.assertEquals(2, searchDocuments("after:2010 before:2040-08", document1Token)); Assert.assertEquals(1, searchDocuments("tag:super", document1Token)); Assert.assertEquals(1, searchDocuments("shared:yes", document1Token)); - Assert.assertEquals(1, searchDocuments("lang:eng", document1Token)); + Assert.assertEquals(2, searchDocuments("lang:eng", document1Token)); Assert.assertEquals(1, searchDocuments("after:2010 before:2040-08 tag:super shared:yes lang:eng title description full:uranium", document1Token)); // Search documents (nothing) @@ -199,7 +209,7 @@ public class TestDocumentResource extends BaseJerseyTest { Assert.assertEquals(0, searchDocuments("tag:Nop", document1Token)); Assert.assertEquals(0, searchDocuments("lang:fra", document1Token)); - // Get a document + // Get document 1 json = target().path("/document/" + document1Id).request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token) .get(JsonObject.class); @@ -225,6 +235,20 @@ public class TestDocumentResource extends BaseJerseyTest { JsonArray contributors = json.getJsonArray("contributors"); Assert.assertEquals(1, contributors.size()); Assert.assertEquals("document1", contributors.getJsonObject(0).getString("username")); + JsonArray relations = json.getJsonArray("relations"); + Assert.assertEquals(1, relations.size()); + Assert.assertEquals(document2Id, relations.getJsonObject(0).getString("id")); + Assert.assertEquals("My super title document 2", relations.getJsonObject(0).getString("title")); + + // Get document 2 + json = target().path("/document/" + document2Id).request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token) + .get(JsonObject.class); + Assert.assertEquals(document2Id, json.getString("id")); + relations = json.getJsonArray("relations"); + Assert.assertEquals(1, relations.size()); + Assert.assertEquals(document1Id, relations.getJsonObject(0).getString("id")); + Assert.assertEquals("My super title document 1", relations.getJsonObject(0).getString("title")); // Export a document in PDF format Response response = target().path("/document/" + document1Id).request() @@ -241,7 +265,7 @@ public class TestDocumentResource extends BaseJerseyTest { String tag2Id = json.getString("id"); Assert.assertNotNull(tag1Id); - // Update a document + // Update document 1 json = target().path("/document/" + document1Id).request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token) .post(Entity.form(new Form() @@ -258,14 +282,24 @@ public class TestDocumentResource extends BaseJerseyTest { .param("tags", tag2Id)), JsonObject.class); Assert.assertEquals(document1Id, json.getString("id")); + // Update document 2 + json = target().path("/document/" + document2Id).request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token) + .post(Entity.form(new Form() + .param("title", "My super title document 2") + .param("lang", "eng")), JsonObject.class); + Assert.assertEquals(document2Id, json.getString("id")); + // Search documents by query json = target().path("/document/list") - .queryParam("search", "super") + .queryParam("search", "new") .request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token) .get(JsonObject.class); + documents = json.getJsonArray("documents"); + Assert.assertTrue(documents.size() == 1); - // Get a document + // Get document 1 json = target().path("/document/" + document1Id).request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token) .get(JsonObject.class); @@ -285,6 +319,15 @@ public class TestDocumentResource extends BaseJerseyTest { contributors = json.getJsonArray("contributors"); Assert.assertEquals(1, contributors.size()); Assert.assertEquals("document1", contributors.getJsonObject(0).getString("username")); + relations = json.getJsonArray("relations"); + Assert.assertEquals(0, relations.size()); + + // Get document 2 + json = target().path("/document/" + document1Id).request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token) + .get(JsonObject.class); + relations = json.getJsonArray("relations"); + Assert.assertEquals(0, relations.size()); // Deletes a document json = target().path("/document/" + document1Id).request()