mirror of
https://github.com/sismics/docs.git
synced 2024-11-22 14:07:55 +01:00
Closes #14: Soft delete on DocumentTag + audit log ordering
This commit is contained in:
parent
86cae53789
commit
08e4f6ddae
@ -55,31 +55,50 @@ public class TagDao {
|
|||||||
/**
|
/**
|
||||||
* Update tags on a document.
|
* Update tags on a document.
|
||||||
*
|
*
|
||||||
* @param documentId
|
* @param documentId Document ID
|
||||||
* @param tagIdSet
|
* @param tagIdSet Set of tag ID
|
||||||
*/
|
*/
|
||||||
public void updateTagList(String documentId, Set<String> tagIdSet) {
|
public void updateTagList(String documentId, Set<String> tagIdSet) {
|
||||||
// Delete old tag links
|
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||||
Query q = em.createQuery("delete DocumentTag dt where dt.documentId = :documentId");
|
|
||||||
q.setParameter("documentId", documentId);
|
|
||||||
q.executeUpdate();
|
|
||||||
|
|
||||||
// Create new tag links
|
// Get current tag links
|
||||||
for (String tagId : tagIdSet) {
|
Query q = em.createQuery("select dt from DocumentTag dt where dt.documentId = :documentId and dt.deleteDate is null");
|
||||||
DocumentTag documentTag = new DocumentTag();
|
q.setParameter("documentId", documentId);
|
||||||
documentTag.setId(UUID.randomUUID().toString());
|
@SuppressWarnings("unchecked")
|
||||||
documentTag.setDocumentId(documentId);
|
List<DocumentTag> documentTagList = q.getResultList();
|
||||||
documentTag.setTagId(tagId);
|
|
||||||
em.persist(documentTag);
|
// Deleting tags no longer linked
|
||||||
|
for (DocumentTag documentTag : documentTagList) {
|
||||||
|
if (!tagIdSet.contains(documentTag.getTagId())) {
|
||||||
|
documentTag.setDeleteDate(new Date());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adding new tag links
|
||||||
|
for (String tagId : tagIdSet) {
|
||||||
|
boolean found = false;
|
||||||
|
for (DocumentTag documentTag : documentTagList) {
|
||||||
|
if (documentTag.getTagId().equals(tagId)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
DocumentTag documentTag = new DocumentTag();
|
||||||
|
documentTag.setId(UUID.randomUUID().toString());
|
||||||
|
documentTag.setDocumentId(documentId);
|
||||||
|
documentTag.setTagId(tagId);
|
||||||
|
em.persist(documentTag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns tag list on a document.
|
* Returns tag list on a document.
|
||||||
* @param documentId
|
*
|
||||||
* @return
|
* @param documentId Document ID
|
||||||
|
* @return List of tags
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public List<TagDto> getByDocumentId(String documentId, String userId) {
|
public List<TagDto> getByDocumentId(String documentId, String userId) {
|
||||||
@ -87,7 +106,7 @@ public class TagDao {
|
|||||||
StringBuilder sb = new StringBuilder("select t.TAG_ID_C, t.TAG_NAME_C, t.TAG_COLOR_C from T_DOCUMENT_TAG dt ");
|
StringBuilder sb = new StringBuilder("select t.TAG_ID_C, t.TAG_NAME_C, t.TAG_COLOR_C from T_DOCUMENT_TAG dt ");
|
||||||
sb.append(" join T_TAG t on t.TAG_ID_C = dt.DOT_IDTAG_C ");
|
sb.append(" join T_TAG t on t.TAG_ID_C = dt.DOT_IDTAG_C ");
|
||||||
sb.append(" where dt.DOT_IDDOCUMENT_C = :documentId and t.TAG_DELETEDATE_D is null ");
|
sb.append(" where dt.DOT_IDDOCUMENT_C = :documentId and t.TAG_DELETEDATE_D is null ");
|
||||||
sb.append(" and t.TAG_IDUSER_C = :userId ");
|
sb.append(" and t.TAG_IDUSER_C = :userId and dt.DOT_DELETEDATE_D is null ");
|
||||||
sb.append(" order by t.TAG_NAME_C ");
|
sb.append(" order by t.TAG_NAME_C ");
|
||||||
|
|
||||||
// Perform the query
|
// Perform the query
|
||||||
@ -111,15 +130,16 @@ public class TagDao {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns stats on tags.
|
* Returns stats on tags.
|
||||||
* @param documentId
|
*
|
||||||
* @return
|
* @param documentId Document ID
|
||||||
|
* @return Stats by tag
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public List<TagStatDto> getStats(String userId) {
|
public List<TagStatDto> getStats(String userId) {
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||||
StringBuilder sb = new StringBuilder("select t.TAG_ID_C, t.TAG_NAME_C, t.TAG_COLOR_C, count(d.DOC_ID_C) ");
|
StringBuilder sb = new StringBuilder("select t.TAG_ID_C, t.TAG_NAME_C, t.TAG_COLOR_C, count(d.DOC_ID_C) ");
|
||||||
sb.append(" from T_TAG t ");
|
sb.append(" from T_TAG t ");
|
||||||
sb.append(" left join T_DOCUMENT_TAG dt on t.TAG_ID_C = dt.DOT_IDTAG_C ");
|
sb.append(" left join T_DOCUMENT_TAG dt on t.TAG_ID_C = dt.DOT_IDTAG_C and dt.DOT_DELETEDATE_D is null ");
|
||||||
sb.append(" left join T_DOCUMENT d on d.DOC_ID_C = dt.DOT_IDDOCUMENT_C and d.DOC_DELETEDATE_D is null and d.DOC_IDUSER_C = :userId ");
|
sb.append(" left join T_DOCUMENT d on d.DOC_ID_C = dt.DOT_IDDOCUMENT_C and d.DOC_DELETEDATE_D is null and d.DOC_IDUSER_C = :userId ");
|
||||||
sb.append(" where t.TAG_IDUSER_C = :userId and t.TAG_DELETEDATE_D is null ");
|
sb.append(" where t.TAG_IDUSER_C = :userId and t.TAG_DELETEDATE_D is null ");
|
||||||
sb.append(" group by t.TAG_ID_C ");
|
sb.append(" group by t.TAG_ID_C ");
|
||||||
@ -168,6 +188,7 @@ public class TagDao {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a tag by name.
|
* Returns a tag by name.
|
||||||
|
*
|
||||||
* @param userId User ID
|
* @param userId User ID
|
||||||
* @param name Name
|
* @param name Name
|
||||||
* @return Tag
|
* @return Tag
|
||||||
@ -186,6 +207,7 @@ public class TagDao {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a tag by ID.
|
* Returns a tag by ID.
|
||||||
|
*
|
||||||
* @param userId User ID
|
* @param userId User ID
|
||||||
* @param tagId Tag ID
|
* @param tagId Tag ID
|
||||||
* @return Tag
|
* @return Tag
|
||||||
@ -216,8 +238,7 @@ public class TagDao {
|
|||||||
Tag tagDb = (Tag) q.getSingleResult();
|
Tag tagDb = (Tag) q.getSingleResult();
|
||||||
|
|
||||||
// Delete the tag
|
// Delete the tag
|
||||||
Date dateNow = new Date();
|
tagDb.setDeleteDate(new Date());
|
||||||
tagDb.setDeleteDate(dateNow);
|
|
||||||
|
|
||||||
// Delete linked data
|
// Delete linked data
|
||||||
q = em.createQuery("delete DocumentTag dt where dt.tagId = :tagId");
|
q = em.createQuery("delete DocumentTag dt where dt.tagId = :tagId");
|
||||||
|
@ -6,7 +6,9 @@ import javax.persistence.Column;
|
|||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Link between a document and a tag.
|
* Link between a document and a tag.
|
||||||
@ -40,6 +42,12 @@ public class DocumentTag implements Serializable {
|
|||||||
@Column(name = "DOT_IDTAG_C", length = 36)
|
@Column(name = "DOT_IDTAG_C", length = 36)
|
||||||
private String tagId;
|
private String tagId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletion date.
|
||||||
|
*/
|
||||||
|
@Column(name = "DOT_DELETEDATE_D")
|
||||||
|
private Date deleteDate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter of id.
|
* Getter of id.
|
||||||
*
|
*
|
||||||
@ -94,44 +102,24 @@ public class DocumentTag implements Serializable {
|
|||||||
this.tagId = tagId;
|
this.tagId = tagId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public int hashCode() {
|
* Getter of deleteDate.
|
||||||
final int prime = 31;
|
*
|
||||||
int result = 1;
|
* @return the deleteDate
|
||||||
result = prime * result + ((documentId == null) ? 0 : documentId.hashCode());
|
*/
|
||||||
result = prime * result + ((tagId == null) ? 0 : tagId.hashCode());
|
public Date getDeleteDate() {
|
||||||
return result;
|
return deleteDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public boolean equals(Object obj) {
|
* Setter of deleteDate.
|
||||||
if (this == obj) {
|
*
|
||||||
return true;
|
* @param deleteDate deleteDate
|
||||||
}
|
*/
|
||||||
if (obj == null) {
|
public void setDeleteDate(Date deleteDate) {
|
||||||
return false;
|
this.deleteDate = deleteDate;
|
||||||
}
|
|
||||||
if (getClass() != obj.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
DocumentTag other = (DocumentTag) obj;
|
|
||||||
if (documentId == null) {
|
|
||||||
if (other.documentId != null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (!documentId.equals(other.documentId)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (tagId == null) {
|
|
||||||
if (other.tagId != null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (!tagId.equals(other.tagId)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return Objects.toStringHelper(this)
|
return Objects.toStringHelper(this)
|
||||||
|
@ -3,4 +3,5 @@ alter table T_AUTHENTICATION_TOKEN add column AUT_IP_C varchar(45);
|
|||||||
alter table T_AUTHENTICATION_TOKEN add column AUT_UA_C varchar(1000);
|
alter table T_AUTHENTICATION_TOKEN add column AUT_UA_C varchar(1000);
|
||||||
create cached table T_AUDIT_LOG ( LOG_ID_C varchar(36) not null, LOG_IDENTITY_C varchar(36) not null, LOG_CLASSENTITY_C varchar(50) not null, LOG_TYPE_C varchar(50) not null, LOG_MESSAGE_C varchar(1000), LOG_CREATEDATE_D datetime, primary key (LOG_ID_C) );
|
create cached table T_AUDIT_LOG ( LOG_ID_C varchar(36) not null, LOG_IDENTITY_C varchar(36) not null, LOG_CLASSENTITY_C varchar(50) not null, LOG_TYPE_C varchar(50) not null, LOG_MESSAGE_C varchar(1000), LOG_CREATEDATE_D datetime, primary key (LOG_ID_C) );
|
||||||
create index IDX_LOG_COMPOSITE on T_AUDIT_LOG (LOG_IDENTITY_C, LOG_CLASSENTITY_C);
|
create index IDX_LOG_COMPOSITE on T_AUDIT_LOG (LOG_IDENTITY_C, LOG_CLASSENTITY_C);
|
||||||
|
alter table T_DOCUMENT_TAG add column DOT_DELETEDATE_D datetime;
|
||||||
update T_CONFIG set CFG_VALUE_C='10' where CFG_ID_C='DB_VERSION';
|
update T_CONFIG set CFG_VALUE_C='10' where CFG_ID_C='DB_VERSION';
|
@ -47,7 +47,7 @@ public class AuditLogResource extends BaseResource {
|
|||||||
|
|
||||||
// On a document or a user?
|
// On a document or a user?
|
||||||
PaginatedList<AuditLogDto> paginatedList = PaginatedLists.create(20, 0);
|
PaginatedList<AuditLogDto> paginatedList = PaginatedLists.create(20, 0);
|
||||||
SortCriteria sortCriteria = new SortCriteria(1, true);
|
SortCriteria sortCriteria = new SortCriteria(1, false);
|
||||||
AuditLogCriteria criteria = new AuditLogCriteria();
|
AuditLogCriteria criteria = new AuditLogCriteria();
|
||||||
if (documentId == null) {
|
if (documentId == null) {
|
||||||
// Search logs for a user
|
// Search logs for a user
|
||||||
|
@ -75,12 +75,61 @@ public class TestTagResource extends BaseJerseyTest {
|
|||||||
documentResource = resource().path("/document");
|
documentResource = resource().path("/document");
|
||||||
documentResource.addFilter(new CookieAuthenticationFilter(tag1Token));
|
documentResource.addFilter(new CookieAuthenticationFilter(tag1Token));
|
||||||
postParams = new MultivaluedMapImpl();
|
postParams = new MultivaluedMapImpl();
|
||||||
postParams.add("title", "My super document 1");
|
postParams.add("title", "My super document 2");
|
||||||
postParams.add("tags", tag4Id);
|
postParams.add("tags", tag4Id);
|
||||||
postParams.add("language", "eng");
|
postParams.add("language", "eng");
|
||||||
response = documentResource.put(ClientResponse.class, postParams);
|
response = documentResource.put(ClientResponse.class, postParams);
|
||||||
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||||
json = response.getEntity(JSONObject.class);
|
json = response.getEntity(JSONObject.class);
|
||||||
|
String document2Id = json.getString("id");
|
||||||
|
|
||||||
|
// Check tags on a document
|
||||||
|
documentResource = resource().path("/document/" + document2Id);
|
||||||
|
documentResource.addFilter(new CookieAuthenticationFilter(tag1Token));
|
||||||
|
response = documentResource.get(ClientResponse.class);
|
||||||
|
json = response.getEntity(JSONObject.class);
|
||||||
|
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||||
|
JSONArray tags = json.getJSONArray("tags");
|
||||||
|
Assert.assertEquals(1, tags.length());
|
||||||
|
Assert.assertEquals(tag4Id, tags.getJSONObject(0).getString("id"));
|
||||||
|
|
||||||
|
// Update tags on a document
|
||||||
|
documentResource = resource().path("/document/" + document2Id);
|
||||||
|
documentResource.addFilter(new CookieAuthenticationFilter(tag1Token));
|
||||||
|
postParams = new MultivaluedMapImpl();
|
||||||
|
postParams.add("tags", tag3Id);
|
||||||
|
postParams.add("tags", tag4Id);
|
||||||
|
response = documentResource.post(ClientResponse.class, postParams);
|
||||||
|
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||||
|
|
||||||
|
// Check tags on a document
|
||||||
|
documentResource = resource().path("/document/" + document2Id);
|
||||||
|
documentResource.addFilter(new CookieAuthenticationFilter(tag1Token));
|
||||||
|
response = documentResource.get(ClientResponse.class);
|
||||||
|
json = response.getEntity(JSONObject.class);
|
||||||
|
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||||
|
tags = json.getJSONArray("tags");
|
||||||
|
Assert.assertEquals(2, tags.length());
|
||||||
|
Assert.assertEquals(tag3Id, tags.getJSONObject(0).getString("id"));
|
||||||
|
Assert.assertEquals(tag4Id, tags.getJSONObject(1).getString("id"));
|
||||||
|
|
||||||
|
// Update tags on a document
|
||||||
|
documentResource = resource().path("/document/" + document2Id);
|
||||||
|
documentResource.addFilter(new CookieAuthenticationFilter(tag1Token));
|
||||||
|
postParams = new MultivaluedMapImpl();
|
||||||
|
postParams.add("tags", tag4Id);
|
||||||
|
response = documentResource.post(ClientResponse.class, postParams);
|
||||||
|
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||||
|
|
||||||
|
// Check tags on a document
|
||||||
|
documentResource = resource().path("/document/" + document2Id);
|
||||||
|
documentResource.addFilter(new CookieAuthenticationFilter(tag1Token));
|
||||||
|
response = documentResource.get(ClientResponse.class);
|
||||||
|
json = response.getEntity(JSONObject.class);
|
||||||
|
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||||
|
tags = json.getJSONArray("tags");
|
||||||
|
Assert.assertEquals(1, tags.length());
|
||||||
|
Assert.assertEquals(tag4Id, tags.getJSONObject(0).getString("id"));
|
||||||
|
|
||||||
// Get tag stats
|
// Get tag stats
|
||||||
tagResource = resource().path("/tag/stats");
|
tagResource = resource().path("/tag/stats");
|
||||||
@ -99,7 +148,7 @@ public class TestTagResource extends BaseJerseyTest {
|
|||||||
response = tagResource.get(ClientResponse.class);
|
response = tagResource.get(ClientResponse.class);
|
||||||
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||||
json = response.getEntity(JSONObject.class);
|
json = response.getEntity(JSONObject.class);
|
||||||
JSONArray tags = json.getJSONArray("tags");
|
tags = json.getJSONArray("tags");
|
||||||
Assert.assertTrue(tags.length() > 0);
|
Assert.assertTrue(tags.length() > 0);
|
||||||
Assert.assertEquals("Tag4", tags.getJSONObject(1).getString("name"));
|
Assert.assertEquals("Tag4", tags.getJSONObject(1).getString("name"));
|
||||||
Assert.assertEquals("#00ff00", tags.getJSONObject(1).getString("color"));
|
Assert.assertEquals("#00ff00", tags.getJSONObject(1).getString("color"));
|
||||||
|
Loading…
Reference in New Issue
Block a user