#67: relations between documents (server-side)

This commit is contained in:
jendib 2016-03-06 21:06:23 +01:00
parent ca8c525de0
commit 0525754337
6 changed files with 237 additions and 56 deletions

View File

@ -184,6 +184,11 @@ public class DocumentDao {
q.setParameter("dateNow", dateNow); q.setParameter("dateNow", dateNow);
q.executeUpdate(); 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 // Create audit log
AuditLogUtil.create(documentDb, AuditLogType.DELETE, userId); AuditLogUtil.create(documentDb, AuditLogType.DELETE, userId);
} }

View File

@ -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<RelationDto> 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<Object[]> l = q.getResultList();
// Assemble results
List<RelationDto> relationDtoList = new ArrayList<RelationDto>();
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<String> 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<Relation> 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);
}
}
}
}

View File

@ -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;
}
}

View File

@ -26,74 +26,34 @@ public class TagDto {
*/ */
private String parentId; private String parentId;
/**
* Getter of id.
*
* @return the id
*/
public String getId() { public String getId() {
return id; return id;
} }
/**
* Setter of id.
*
* @param id id
*/
public void setId(String id) { public void setId(String id) {
this.id = id; this.id = id;
} }
/**
* Getter of name.
*
* @return the name
*/
public String getName() { public String getName() {
return name; return name;
} }
/**
* Setter of name.
*
* @param name name
*/
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
/**
* Getter of color.
*
* @return the color
*/
public String getColor() { public String getColor() {
return color; return color;
} }
/**
* Setter of color.
*
* @param color color
*/
public void setColor(String color) { public void setColor(String color) {
this.color = color; this.color = color;
} }
/**
* Getter of parentId.
*
* @return the parentId
*/
public String getParentId() { public String getParentId() {
return parentId; return parentId;
} }
/**
* Setter of parentId.
*
* @param color parentId
*/
public void setParentId(String parentId) { public void setParentId(String parentId) {
this.parentId = parentId; this.parentId = parentId;
} }

View File

@ -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.ContributorDao;
import com.sismics.docs.core.dao.jpa.DocumentDao; import com.sismics.docs.core.dao.jpa.DocumentDao;
import com.sismics.docs.core.dao.jpa.FileDao; 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.TagDao;
import com.sismics.docs.core.dao.jpa.UserDao; import com.sismics.docs.core.dao.jpa.UserDao;
import com.sismics.docs.core.dao.jpa.criteria.DocumentCriteria; 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.AclDto;
import com.sismics.docs.core.dao.jpa.dto.ContributorDto; 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.DocumentDto;
import com.sismics.docs.core.dao.jpa.dto.RelationDto;
import com.sismics.docs.core.dao.jpa.dto.TagDto; import com.sismics.docs.core.dao.jpa.dto.TagDto;
import com.sismics.docs.core.event.DocumentCreatedAsyncEvent; import com.sismics.docs.core.event.DocumentCreatedAsyncEvent;
import com.sismics.docs.core.event.DocumentDeletedAsyncEvent; import com.sismics.docs.core.event.DocumentDeletedAsyncEvent;
@ -172,6 +174,17 @@ public class DocumentResource extends BaseResource {
} }
document.add("contributors", contributorList); document.add("contributors", contributorList);
// Add relations
RelationDao relationDao = new RelationDao();
List<RelationDto> 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(); return Response.ok().entity(document.build()).build();
} }
@ -430,6 +443,7 @@ public class DocumentResource extends BaseResource {
@FormParam("coverage") String coverage, @FormParam("coverage") String coverage,
@FormParam("rights") String rights, @FormParam("rights") String rights,
@FormParam("tags") List<String> tagList, @FormParam("tags") List<String> tagList,
@FormParam("relations") List<String> relationList,
@FormParam("language") String language, @FormParam("language") String language,
@FormParam("create_date") String createDateStr) { @FormParam("create_date") String createDateStr) {
if (!authenticate()) { if (!authenticate()) {
@ -493,6 +507,9 @@ public class DocumentResource extends BaseResource {
// Update tags // Update tags
updateTagList(documentId, tagList); updateTagList(documentId, tagList);
// Update relations
updateRelationList(documentId, relationList);
// Raise a document created event // Raise a document created event
DocumentCreatedAsyncEvent documentCreatedAsyncEvent = new DocumentCreatedAsyncEvent(); DocumentCreatedAsyncEvent documentCreatedAsyncEvent = new DocumentCreatedAsyncEvent();
documentCreatedAsyncEvent.setUserId(principal.getId()); documentCreatedAsyncEvent.setUserId(principal.getId());
@ -526,6 +543,7 @@ public class DocumentResource extends BaseResource {
@FormParam("coverage") String coverage, @FormParam("coverage") String coverage,
@FormParam("rights") String rights, @FormParam("rights") String rights,
@FormParam("tags") List<String> tagList, @FormParam("tags") List<String> tagList,
@FormParam("relations") List<String> relationList,
@FormParam("language") String language, @FormParam("language") String language,
@FormParam("create_date") String createDateStr) { @FormParam("create_date") String createDateStr) {
if (!authenticate()) { if (!authenticate()) {
@ -600,6 +618,9 @@ public class DocumentResource extends BaseResource {
// Update tags // Update tags
updateTagList(id, tagList); updateTagList(id, tagList);
// Update relations
updateRelationList(id, relationList);
// Raise a document updated event // Raise a document updated event
DocumentUpdatedAsyncEvent documentUpdatedAsyncEvent = new DocumentUpdatedAsyncEvent(); DocumentUpdatedAsyncEvent documentUpdatedAsyncEvent = new DocumentUpdatedAsyncEvent();
documentUpdatedAsyncEvent.setUserId(principal.getId()); 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<String> relationList) {
if (relationList != null) {
DocumentDao documentDao = new DocumentDao();
RelationDao relationDao = new RelationDao();
Set<String> 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. * Deletes a document.
* *

View File

@ -76,6 +76,16 @@ public class TestDocumentResource extends BaseJerseyTest {
String document1Id = json.getString("id"); String document1Id = json.getString("id");
Assert.assertNotNull(document1Id); 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 // Add a file
String file1Id = null; String file1Id = null;
try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) { try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) {
@ -100,13 +110,13 @@ public class TestDocumentResource extends BaseJerseyTest {
// List all documents // List all documents
json = target().path("/document/list") json = target().path("/document/list")
.queryParam("sort_column", 3) .queryParam("sort_column", 3)
.queryParam("asc", false) .queryParam("asc", true)
.request() .request()
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token) .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token)
.get(JsonObject.class); .get(JsonObject.class);
JsonArray documents = json.getJsonArray("documents"); JsonArray documents = json.getJsonArray("documents");
JsonArray tags = documents.getJsonObject(0).getJsonArray("tags"); 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(document1Id, documents.getJsonObject(0).getString("id"));
Assert.assertEquals("eng", documents.getJsonObject(0).getString("language")); Assert.assertEquals("eng", documents.getJsonObject(0).getString("language"));
Assert.assertEquals(1, documents.getJsonObject(0).getInt("file_count")); Assert.assertEquals(1, documents.getJsonObject(0).getInt("file_count"));
@ -130,8 +140,8 @@ public class TestDocumentResource extends BaseJerseyTest {
json = target().path("/document").request() json = target().path("/document").request()
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, document3Token) .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document3Token)
.put(Entity.form(new Form() .put(Entity.form(new Form()
.param("title", "My super title document 1") .param("title", "My super title document 3")
.param("description", "My super description for document 1") .param("description", "My super description for document 3")
.param("language", "eng") .param("language", "eng")
.param("create_date", Long.toString(create3Date))), JsonObject.class); .param("create_date", Long.toString(create3Date))), JsonObject.class);
String document3Id = json.getString("id"); String document3Id = json.getString("id");
@ -165,8 +175,8 @@ public class TestDocumentResource extends BaseJerseyTest {
// Search documents // Search documents
Assert.assertEquals(1, searchDocuments("full:uranium full:einstein", document1Token)); Assert.assertEquals(1, searchDocuments("full:uranium full:einstein", document1Token));
Assert.assertEquals(1, searchDocuments("full:title", document1Token)); Assert.assertEquals(2, searchDocuments("full:title", document1Token));
Assert.assertEquals(1, searchDocuments("title", document1Token)); Assert.assertEquals(2, searchDocuments("title", document1Token));
Assert.assertEquals(1, searchDocuments("super description", document1Token)); Assert.assertEquals(1, searchDocuments("super description", document1Token));
Assert.assertEquals(1, searchDocuments("subject", document1Token)); Assert.assertEquals(1, searchDocuments("subject", document1Token));
Assert.assertEquals(1, searchDocuments("identifier", 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("greenland", document1Token));
Assert.assertEquals(1, searchDocuments("public domain", document1Token)); Assert.assertEquals(1, searchDocuments("public domain", document1Token));
Assert.assertEquals(0, searchDocuments("by:document3", 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(0, searchDocuments("by:nobody", document1Token));
Assert.assertEquals(1, searchDocuments("at:" + DateTimeFormat.forPattern("yyyy").print(new Date().getTime()), document1Token)); Assert.assertEquals(2, 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(2, 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(2, 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("after:2010 before:2040-08", document1Token));
Assert.assertEquals(1, searchDocuments("tag:super", document1Token)); Assert.assertEquals(1, searchDocuments("tag:super", document1Token));
Assert.assertEquals(1, searchDocuments("shared:yes", 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)); Assert.assertEquals(1, searchDocuments("after:2010 before:2040-08 tag:super shared:yes lang:eng title description full:uranium", document1Token));
// Search documents (nothing) // Search documents (nothing)
@ -199,7 +209,7 @@ public class TestDocumentResource extends BaseJerseyTest {
Assert.assertEquals(0, searchDocuments("tag:Nop", document1Token)); Assert.assertEquals(0, searchDocuments("tag:Nop", document1Token));
Assert.assertEquals(0, searchDocuments("lang:fra", document1Token)); Assert.assertEquals(0, searchDocuments("lang:fra", document1Token));
// Get a document // Get document 1
json = target().path("/document/" + document1Id).request() json = target().path("/document/" + document1Id).request()
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token) .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token)
.get(JsonObject.class); .get(JsonObject.class);
@ -225,6 +235,20 @@ public class TestDocumentResource extends BaseJerseyTest {
JsonArray contributors = json.getJsonArray("contributors"); JsonArray contributors = json.getJsonArray("contributors");
Assert.assertEquals(1, contributors.size()); Assert.assertEquals(1, contributors.size());
Assert.assertEquals("document1", contributors.getJsonObject(0).getString("username")); 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 // Export a document in PDF format
Response response = target().path("/document/" + document1Id).request() Response response = target().path("/document/" + document1Id).request()
@ -241,7 +265,7 @@ public class TestDocumentResource extends BaseJerseyTest {
String tag2Id = json.getString("id"); String tag2Id = json.getString("id");
Assert.assertNotNull(tag1Id); Assert.assertNotNull(tag1Id);
// Update a document // Update document 1
json = target().path("/document/" + document1Id).request() json = target().path("/document/" + document1Id).request()
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token) .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token)
.post(Entity.form(new Form() .post(Entity.form(new Form()
@ -258,14 +282,24 @@ public class TestDocumentResource extends BaseJerseyTest {
.param("tags", tag2Id)), JsonObject.class); .param("tags", tag2Id)), JsonObject.class);
Assert.assertEquals(document1Id, json.getString("id")); 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 // Search documents by query
json = target().path("/document/list") json = target().path("/document/list")
.queryParam("search", "super") .queryParam("search", "new")
.request() .request()
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token) .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token)
.get(JsonObject.class); .get(JsonObject.class);
documents = json.getJsonArray("documents");
Assert.assertTrue(documents.size() == 1);
// Get a document // Get document 1
json = target().path("/document/" + document1Id).request() json = target().path("/document/" + document1Id).request()
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token) .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token)
.get(JsonObject.class); .get(JsonObject.class);
@ -285,6 +319,15 @@ public class TestDocumentResource extends BaseJerseyTest {
contributors = json.getJsonArray("contributors"); contributors = json.getJsonArray("contributors");
Assert.assertEquals(1, contributors.size()); Assert.assertEquals(1, contributors.size());
Assert.assertEquals("document1", contributors.getJsonObject(0).getString("username")); 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 // Deletes a document
json = target().path("/document/" + document1Id).request() json = target().path("/document/" + document1Id).request()