#23: Tag tree (server)

This commit is contained in:
jendib 2015-09-13 23:54:06 +02:00
parent 50c7066f88
commit cfde218d32
11 changed files with 91 additions and 11 deletions

View File

@ -103,7 +103,7 @@ public class TagDao {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public List<TagDto> getByDocumentId(String documentId, String userId) { public List<TagDto> getByDocumentId(String documentId, 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 from T_DOCUMENT_TAG dt "); StringBuilder sb = new StringBuilder("select t.TAG_ID_C, t.TAG_NAME_C, t.TAG_COLOR_C, t.TAG_IDPARENT_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 and dt.DOT_DELETEDATE_D is null "); sb.append(" and t.TAG_IDUSER_C = :userId and dt.DOT_DELETEDATE_D is null ");
@ -123,6 +123,7 @@ public class TagDao {
tagDto.setId((String) o[i++]); tagDto.setId((String) o[i++]);
tagDto.setName((String) o[i++]); tagDto.setName((String) o[i++]);
tagDto.setColor((String) o[i++]); tagDto.setColor((String) o[i++]);
tagDto.setParentId((String) o[i++]);
tagDtoList.add(tagDto); tagDtoList.add(tagDto);
} }
return tagDtoList; return tagDtoList;
@ -137,7 +138,7 @@ public class TagDao {
@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, t.TAG_IDPARENT_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 and dt.DOT_DELETEDATE_D is null "); 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 ");
@ -158,6 +159,7 @@ public class TagDao {
tagDto.setId((String) o[i++]); tagDto.setId((String) o[i++]);
tagDto.setName((String) o[i++]); tagDto.setName((String) o[i++]);
tagDto.setColor((String) o[i++]); tagDto.setColor((String) o[i++]);
tagDto.setParentId((String) o[i++]);
tagDto.setCount(((Number) o[i++]).intValue()); tagDto.setCount(((Number) o[i++]).intValue());
tagStatDtoList.add(tagDto); tagStatDtoList.add(tagDto);
} }
@ -281,6 +283,7 @@ public class TagDao {
// Update the tag // Update the tag
tagFromDb.setName(tag.getName()); tagFromDb.setName(tag.getName());
tagFromDb.setColor(tag.getColor()); tagFromDb.setColor(tag.getColor());
tagFromDb.setParentId(tag.getParentId());
// Create audit log // Create audit log
AuditLogUtil.create(tagFromDb, AuditLogType.UPDATE); AuditLogUtil.create(tagFromDb, AuditLogType.UPDATE);

View File

@ -23,6 +23,11 @@ public class TagDto {
* Color. * Color.
*/ */
private String color; private String color;
/**
* Parent ID.
*/
private String parentId;
/** /**
* Getter of id. * Getter of id.
@ -77,4 +82,22 @@ public class TagDto {
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() {
return parentId;
}
/**
* Setter of parentId.
*
* @param color parentId
*/
public void setParentId(String parentId) {
this.parentId = parentId;
}
} }

View File

@ -2,7 +2,7 @@ package com.sismics.docs.core.dao.jpa.dto;
/** /**
* Tag DTO. * Tag stat DTO.
* *
* @author bgamard * @author bgamard
*/ */

View File

@ -39,6 +39,12 @@ public class Tag implements Loggable {
@Column(name = "TAG_IDUSER_C", nullable = false, length = 36) @Column(name = "TAG_IDUSER_C", nullable = false, length = 36)
private String userId; private String userId;
/**
* User ID.
*/
@Column(name = "TAG_IDPARENT_C", length = 36)
private String parentId;
/** /**
* Creation date. * Creation date.
*/ */
@ -165,12 +171,31 @@ public class Tag implements Loggable {
public void setDeleteDate(Date deleteDate) { public void setDeleteDate(Date deleteDate) {
this.deleteDate = deleteDate; this.deleteDate = deleteDate;
} }
/**
* Getter of parentId.
*
* @return parentId
*/
public String getParentId() {
return parentId;
}
/**
* Setter of parentId.
*
* @param parentId parentId
*/
public void setParentId(String parentId) {
this.parentId = parentId;
}
@Override @Override
public String toString() { public String toString() {
return MoreObjects.toStringHelper(this) return MoreObjects.toStringHelper(this)
.add("id", id) .add("id", id)
.add("name", name) .add("name", name)
.add("parentId", parentId)
.toString(); .toString();
} }

View File

@ -1 +1 @@
db.version=1 db.version=2

View File

@ -0,0 +1,2 @@
alter table T_TAG add column TAG_IDPARENT_C varchar(36);
update T_CONFIG set CFG_VALUE_C = '2' where CFG_ID_C = 'DB_VERSION';

View File

@ -1,3 +1,3 @@
api.current_version=${project.version} api.current_version=${project.version}
api.min_version=1.0 api.min_version=1.0
db.version=1 db.version=2

View File

@ -22,6 +22,7 @@ import com.sismics.docs.core.dao.jpa.dto.TagStatDto;
import com.sismics.docs.core.model.jpa.Tag; import com.sismics.docs.core.model.jpa.Tag;
import com.sismics.rest.exception.ClientException; import com.sismics.rest.exception.ClientException;
import com.sismics.rest.exception.ForbiddenClientException; import com.sismics.rest.exception.ForbiddenClientException;
import com.sismics.rest.util.JsonUtil;
import com.sismics.rest.util.ValidationUtil; import com.sismics.rest.util.ValidationUtil;
/** /**
@ -50,7 +51,8 @@ public class TagResource extends BaseResource {
items.add(Json.createObjectBuilder() items.add(Json.createObjectBuilder()
.add("id", tag.getId()) .add("id", tag.getId())
.add("name", tag.getName()) .add("name", tag.getName())
.add("color", tag.getColor())); .add("color", tag.getColor())
.add("parent", JsonUtil.nullable(tag.getParentId())));
} }
JsonObjectBuilder response = Json.createObjectBuilder() JsonObjectBuilder response = Json.createObjectBuilder()
@ -96,7 +98,8 @@ public class TagResource extends BaseResource {
@PUT @PUT
public Response add( public Response add(
@FormParam("name") String name, @FormParam("name") String name,
@FormParam("color") String color) { @FormParam("color") String color,
@FormParam("parent") String parentId) {
if (!authenticate()) { if (!authenticate()) {
throw new ForbiddenClientException(); throw new ForbiddenClientException();
} }
@ -117,11 +120,20 @@ public class TagResource extends BaseResource {
throw new ClientException("AlreadyExistingTag", MessageFormat.format("Tag already exists: {0}", name)); throw new ClientException("AlreadyExistingTag", MessageFormat.format("Tag already exists: {0}", name));
} }
// Check the parent
if (parentId != null) {
Tag parentTag = tagDao.getByTagId(principal.getId(), parentId);
if (parentTag == null) {
throw new ClientException("ParentNotFound", MessageFormat.format("Parent not found: {0}", parentId));
}
}
// Create the tag // Create the tag
tag = new Tag(); tag = new Tag();
tag.setName(name); tag.setName(name);
tag.setColor(color); tag.setColor(color);
tag.setUserId(principal.getId()); tag.setUserId(principal.getId());
tag.setParentId(parentId);
String id = tagDao.create(tag); String id = tagDao.create(tag);
JsonObjectBuilder response = Json.createObjectBuilder() JsonObjectBuilder response = Json.createObjectBuilder()
@ -140,7 +152,8 @@ public class TagResource extends BaseResource {
public Response update( public Response update(
@PathParam("id") String id, @PathParam("id") String id,
@FormParam("name") String name, @FormParam("name") String name,
@FormParam("color") String color) { @FormParam("color") String color,
@FormParam("parent") String parentId) {
if (!authenticate()) { if (!authenticate()) {
throw new ForbiddenClientException(); throw new ForbiddenClientException();
} }
@ -161,6 +174,14 @@ public class TagResource extends BaseResource {
throw new ClientException("TagNotFound", MessageFormat.format("Tag not found: {0}", id)); throw new ClientException("TagNotFound", MessageFormat.format("Tag not found: {0}", id));
} }
// Check the parent
if (parentId != null) {
Tag parentTag = tagDao.getByTagId(principal.getId(), parentId);
if (parentTag == null) {
throw new ClientException("ParentNotFound", MessageFormat.format("Parent not found: {0}", parentId));
}
}
// Check for name duplicate // Check for name duplicate
Tag tagDuplicate = tagDao.getByName(principal.getId(), name); Tag tagDuplicate = tagDao.getByName(principal.getId(), name);
if (tagDuplicate != null && !tagDuplicate.getId().equals(id)) { if (tagDuplicate != null && !tagDuplicate.getId().equals(id)) {
@ -174,6 +195,8 @@ public class TagResource extends BaseResource {
if (!StringUtils.isEmpty(color)) { if (!StringUtils.isEmpty(color)) {
tag.setColor(color); tag.setColor(color);
} }
// Parent tag is always updated to have the possibility to delete it
tag.setParentId(parentId);
tagDao.update(tag); tagDao.update(tag);

View File

@ -1,3 +1,3 @@
api.current_version=${project.version} api.current_version=${project.version}
api.min_version=1.0 api.min_version=1.0
db.version=1 db.version=2

View File

@ -1,3 +1,3 @@
api.current_version=${project.version} api.current_version=${project.version}
api.min_version=1.0 api.min_version=1.0
db.version=1 db.version=2

View File

@ -2,6 +2,7 @@ package com.sismics.docs.rest;
import javax.json.JsonArray; import javax.json.JsonArray;
import javax.json.JsonObject; import javax.json.JsonObject;
import javax.json.JsonValue;
import javax.ws.rs.client.Entity; import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Form; import javax.ws.rs.core.Form;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
@ -44,7 +45,8 @@ public class TestTagResource extends BaseJerseyTest {
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, tag1Token) .cookie(TokenBasedSecurityFilter.COOKIE_NAME, tag1Token)
.put(Entity.form(new Form() .put(Entity.form(new Form()
.param("name", "Tag4") .param("name", "Tag4")
.param("color", "#00ff00")), JsonObject.class); .param("color", "#00ff00")
.param("parent", tag3Id)), JsonObject.class);
String tag4Id = json.getString("id"); String tag4Id = json.getString("id");
Assert.assertNotNull(tag4Id); Assert.assertNotNull(tag4Id);
@ -129,6 +131,7 @@ public class TestTagResource extends BaseJerseyTest {
Assert.assertTrue(tags.size() > 0); Assert.assertTrue(tags.size() > 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"));
Assert.assertEquals(tag3Id, tags.getJsonObject(1).getString("parent"));
// Update a tag // Update a tag
json = target().path("/tag/" + tag4Id).request() json = target().path("/tag/" + tag4Id).request()
@ -146,6 +149,7 @@ public class TestTagResource extends BaseJerseyTest {
Assert.assertTrue(tags.size() > 0); Assert.assertTrue(tags.size() > 0);
Assert.assertEquals("UpdatedName", tags.getJsonObject(1).getString("name")); Assert.assertEquals("UpdatedName", tags.getJsonObject(1).getString("name"));
Assert.assertEquals("#0000ff", tags.getJsonObject(1).getString("color")); Assert.assertEquals("#0000ff", tags.getJsonObject(1).getString("color"));
Assert.assertEquals(JsonValue.NULL, tags.getJsonObject(1).get("parent"));
// Deletes a tag // Deletes a tag
target().path("/tag/" + tag4Id).request() target().path("/tag/" + tag4Id).request()