Closes #14: Soft delete on DocumentTag + audit log ordering

This commit is contained in:
jendib 2015-08-28 01:02:33 +02:00
parent 86cae53789
commit 08e4f6ddae
5 changed files with 119 additions and 60 deletions

View File

@ -55,31 +55,50 @@ public class TagDao {
/**
* Update tags on a document.
*
* @param documentId
* @param tagIdSet
* @param documentId Document ID
* @param tagIdSet Set of tag ID
*/
public void updateTagList(String documentId, Set<String> tagIdSet) {
// Delete old tag links
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
Query q = em.createQuery("select dt from DocumentTag dt where dt.documentId = :documentId and dt.deleteDate is null");
q.setParameter("documentId", documentId);
@SuppressWarnings("unchecked")
List<DocumentTag> documentTagList = q.getResultList();
// 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.
* @param documentId
* @return
*
* @param documentId Document ID
* @return List of tags
*/
@SuppressWarnings("unchecked")
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 ");
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(" 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 ");
// Perform the query
@ -111,15 +130,16 @@ public class TagDao {
/**
* Returns stats on tags.
* @param documentId
* @return
*
* @param documentId Document ID
* @return Stats by tag
*/
@SuppressWarnings("unchecked")
public List<TagStatDto> getStats(String userId) {
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) ");
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(" where t.TAG_IDUSER_C = :userId and t.TAG_DELETEDATE_D is null ");
sb.append(" group by t.TAG_ID_C ");
@ -168,6 +188,7 @@ public class TagDao {
/**
* Returns a tag by name.
*
* @param userId User ID
* @param name Name
* @return Tag
@ -186,6 +207,7 @@ public class TagDao {
/**
* Returns a tag by ID.
*
* @param userId User ID
* @param tagId Tag ID
* @return Tag
@ -216,8 +238,7 @@ public class TagDao {
Tag tagDb = (Tag) q.getSingleResult();
// Delete the tag
Date dateNow = new Date();
tagDb.setDeleteDate(dateNow);
tagDb.setDeleteDate(new Date());
// Delete linked data
q = em.createQuery("delete DocumentTag dt where dt.tagId = :tagId");

View File

@ -6,7 +6,9 @@ import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
import java.util.Date;
/**
* Link between a document and a tag.
@ -40,6 +42,12 @@ public class DocumentTag implements Serializable {
@Column(name = "DOT_IDTAG_C", length = 36)
private String tagId;
/**
* Deletion date.
*/
@Column(name = "DOT_DELETEDATE_D")
private Date deleteDate;
/**
* Getter of id.
*
@ -94,42 +102,22 @@ public class DocumentTag implements Serializable {
this.tagId = tagId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((documentId == null) ? 0 : documentId.hashCode());
result = prime * result + ((tagId == null) ? 0 : tagId.hashCode());
return result;
/**
* Getter of deleteDate.
*
* @return the deleteDate
*/
public Date getDeleteDate() {
return deleteDate;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
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;
/**
* Setter of deleteDate.
*
* @param deleteDate deleteDate
*/
public void setDeleteDate(Date deleteDate) {
this.deleteDate = deleteDate;
}
@Override

View File

@ -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);
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);
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';

View File

@ -47,7 +47,7 @@ public class AuditLogResource extends BaseResource {
// On a document or a user?
PaginatedList<AuditLogDto> paginatedList = PaginatedLists.create(20, 0);
SortCriteria sortCriteria = new SortCriteria(1, true);
SortCriteria sortCriteria = new SortCriteria(1, false);
AuditLogCriteria criteria = new AuditLogCriteria();
if (documentId == null) {
// Search logs for a user

View File

@ -75,12 +75,61 @@ public class TestTagResource extends BaseJerseyTest {
documentResource = resource().path("/document");
documentResource.addFilter(new CookieAuthenticationFilter(tag1Token));
postParams = new MultivaluedMapImpl();
postParams.add("title", "My super document 1");
postParams.add("title", "My super document 2");
postParams.add("tags", tag4Id);
postParams.add("language", "eng");
response = documentResource.put(ClientResponse.class, postParams);
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
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
tagResource = resource().path("/tag/stats");
@ -99,7 +148,7 @@ public class TestTagResource extends BaseJerseyTest {
response = tagResource.get(ClientResponse.class);
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
json = response.getEntity(JSONObject.class);
JSONArray tags = json.getJSONArray("tags");
tags = json.getJSONArray("tags");
Assert.assertTrue(tags.length() > 0);
Assert.assertEquals("Tag4", tags.getJSONObject(1).getString("name"));
Assert.assertEquals("#00ff00", tags.getJSONObject(1).getString("color"));