diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/TagDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/TagDao.java index fe780e36..83c97365 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/TagDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/TagDao.java @@ -213,7 +213,7 @@ public class TagDao { Map parameterMap = new HashMap<>(); List criteriaList = new ArrayList<>(); - StringBuilder sb = new StringBuilder("select t.TAG_ID_C as c0, t.TAG_NAME_C as c1, t.TAG_COLOR_C as c2, t.TAG_IDPARENT_C as c3 "); + StringBuilder sb = new StringBuilder("select distinct t.TAG_ID_C as c0, t.TAG_NAME_C as c1, t.TAG_COLOR_C as c2, t.TAG_IDPARENT_C as c3 "); sb.append(" from T_TAG t "); // Add search criterias @@ -223,6 +223,7 @@ public class TagDao { } if (criteria.getTargetIdList() != null) { sb.append(" left join T_ACL a on a.ACL_TARGETID_C in (:targetIdList) and a.ACL_SOURCEID_C = t.TAG_ID_C and a.ACL_PERM_C = 'READ' and a.ACL_DELETEDATE_D is null "); + criteriaList.add("a.ACL_ID_C is not null"); parameterMap.put("targetIdList", criteria.getTargetIdList()); } if (criteria.getDocumentId() != null) { diff --git a/docs-web-common/src/test/java/com/sismics/docs/rest/BaseJerseyTest.java b/docs-web-common/src/test/java/com/sismics/docs/rest/BaseJerseyTest.java index 704d17ea..e4244d6f 100644 --- a/docs-web-common/src/test/java/com/sismics/docs/rest/BaseJerseyTest.java +++ b/docs-web-common/src/test/java/com/sismics/docs/rest/BaseJerseyTest.java @@ -30,7 +30,7 @@ public abstract class BaseJerseyTest extends JerseyTest { /** * Test HTTP server. */ - protected HttpServer httpServer; + private HttpServer httpServer; /** * Utility class for the REST client. @@ -45,7 +45,11 @@ public abstract class BaseJerseyTest extends JerseyTest { @Override protected Application configure() { enable(TestProperties.LOG_TRAFFIC); - // enable(TestProperties.DUMP_ENTITY); + String travisEnv = System.getenv("TRAVIS"); + if (travisEnv == null || !travisEnv.equals("true")) { + // Travis don't like entity dumped in the logs + enable(TestProperties.DUMP_ENTITY); + } return new Application(); } diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/AuditLogResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/AuditLogResource.java index 2d42e01e..83f5b798 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/AuditLogResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/AuditLogResource.java @@ -1,14 +1,5 @@ package com.sismics.docs.rest.resource; -import javax.json.Json; -import javax.json.JsonArrayBuilder; -import javax.json.JsonObjectBuilder; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; - import com.google.common.base.Strings; import com.sismics.docs.core.constant.PermType; import com.sismics.docs.core.dao.jpa.AclDao; @@ -21,6 +12,15 @@ import com.sismics.docs.core.util.jpa.SortCriteria; import com.sismics.rest.exception.ForbiddenClientException; import com.sismics.rest.util.JsonUtil; +import javax.json.Json; +import javax.json.JsonArrayBuilder; +import javax.json.JsonObjectBuilder; +import javax.ws.rs.GET; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Response; + /** * Audit log REST resources. * @@ -50,7 +50,7 @@ public class AuditLogResource extends BaseResource { // Check ACL on the document AclDao aclDao = new AclDao(); if (!aclDao.checkPermission(documentId, PermType.READ, getTargetIdList(null))) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } criteria.setDocumentId(documentId); } diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/CommentResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/CommentResource.java index 26a1881f..bd032dcd 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/CommentResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/CommentResource.java @@ -1,20 +1,5 @@ package com.sismics.docs.rest.resource; -import java.util.List; - -import javax.json.Json; -import javax.json.JsonArrayBuilder; -import javax.json.JsonObjectBuilder; -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; - import com.sismics.docs.core.constant.PermType; import com.sismics.docs.core.dao.jpa.CommentDao; import com.sismics.docs.core.dao.jpa.DocumentDao; @@ -24,6 +9,13 @@ import com.sismics.rest.exception.ForbiddenClientException; import com.sismics.rest.util.ValidationUtil; import com.sismics.util.ImageUtil; +import javax.json.Json; +import javax.json.JsonArrayBuilder; +import javax.json.JsonObjectBuilder; +import javax.ws.rs.*; +import javax.ws.rs.core.Response; +import java.util.List; + /** * Comment REST resource. * @@ -52,7 +44,7 @@ public class CommentResource extends BaseResource { // Read access on doc gives access to write comments DocumentDao documentDao = new DocumentDao(); if (documentDao.getDocument(documentId, PermType.READ, getTargetIdList(null)) == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Create the comment @@ -90,7 +82,7 @@ public class CommentResource extends BaseResource { CommentDao commentDao = new CommentDao(); Comment comment = commentDao.getActiveById(id); if (comment == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // If the current user owns the comment, skip ACL check @@ -98,7 +90,7 @@ public class CommentResource extends BaseResource { // Get the associated document DocumentDao documentDao = new DocumentDao(); if (documentDao.getDocument(comment.getDocumentId(), PermType.WRITE, getTargetIdList(null)) == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } } @@ -126,7 +118,7 @@ public class CommentResource extends BaseResource { // Read access on doc gives access to read comments DocumentDao documentDao = new DocumentDao(); if (documentDao.getDocument(documentId, PermType.READ, getTargetIdList(shareId)) == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Assemble results 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 acb156e7..a7175486 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 @@ -1,57 +1,14 @@ package com.sismics.docs.rest.resource; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; - -import javax.json.Json; -import javax.json.JsonArrayBuilder; -import javax.json.JsonObjectBuilder; -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.StreamingOutput; - -import com.sismics.docs.core.dao.jpa.criteria.TagCriteria; -import org.joda.time.DateTime; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; -import org.joda.time.format.DateTimeFormatterBuilder; -import org.joda.time.format.DateTimeParser; - import com.google.common.base.Joiner; import com.google.common.base.Strings; import com.google.common.io.ByteStreams; import com.sismics.docs.core.constant.Constants; import com.sismics.docs.core.constant.PermType; -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.*; 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.dao.jpa.criteria.TagCriteria; +import com.sismics.docs.core.dao.jpa.dto.*; import com.sismics.docs.core.event.DocumentCreatedAsyncEvent; import com.sismics.docs.core.event.DocumentDeletedAsyncEvent; import com.sismics.docs.core.event.DocumentUpdatedAsyncEvent; @@ -60,7 +17,6 @@ import com.sismics.docs.core.model.context.AppContext; import com.sismics.docs.core.model.jpa.Acl; import com.sismics.docs.core.model.jpa.Document; import com.sismics.docs.core.model.jpa.File; -import com.sismics.docs.core.model.jpa.Tag; import com.sismics.docs.core.model.jpa.User; import com.sismics.docs.core.util.PdfUtil; import com.sismics.docs.core.util.jpa.PaginatedList; @@ -72,6 +28,23 @@ import com.sismics.rest.exception.ServerException; import com.sismics.rest.util.JsonUtil; import com.sismics.rest.util.ValidationUtil; import com.sismics.util.mime.MimeType; +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.DateTimeFormatterBuilder; +import org.joda.time.format.DateTimeParser; + +import javax.json.Json; +import javax.json.JsonArrayBuilder; +import javax.json.JsonObjectBuilder; +import javax.ws.rs.*; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.text.MessageFormat; +import java.util.*; /** * Document REST resources. @@ -98,7 +71,7 @@ public class DocumentResource extends BaseResource { AclDao aclDao = new AclDao(); DocumentDto documentDto = documentDao.getDocument(documentId, PermType.READ, getTargetIdList(shareId)); if (documentDto == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } JsonObjectBuilder document = Json.createObjectBuilder() @@ -215,7 +188,7 @@ public class DocumentResource extends BaseResource { DocumentDao documentDao = new DocumentDao(); final DocumentDto documentDto = documentDao.getDocument(documentId, PermType.READ, getTargetIdList(shareId)); if (documentDto == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Get files @@ -606,7 +579,7 @@ public class DocumentResource extends BaseResource { DocumentDao documentDao = new DocumentDao(); Document document = documentDao.getById(id); if (document == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Update the document @@ -712,7 +685,7 @@ public class DocumentResource extends BaseResource { FileDao fileDao = new FileDao(); DocumentDto documentDto = documentDao.getDocument(id, PermType.WRITE, getTargetIdList(null)); if (documentDto == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } List fileList = fileDao.getByDocumentId(principal.getId(), id); diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/FileResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/FileResource.java index 084eb13b..31a3af3a 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/FileResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/FileResource.java @@ -16,17 +16,7 @@ import java.util.zip.ZipOutputStream; import javax.json.Json; import javax.json.JsonArrayBuilder; import javax.json.JsonObjectBuilder; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.WebApplicationException; +import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; @@ -100,7 +90,7 @@ public class FileResource extends BaseResource { DocumentDao documentDao = new DocumentDao(); documentDto = documentDao.getDocument(documentId, PermType.WRITE, getTargetIdList(null)); if (documentDto == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } } @@ -215,7 +205,7 @@ public class FileResource extends BaseResource { File file = fileDao.getFile(id, principal.getId()); DocumentDto documentDto = documentDao.getDocument(documentId, PermType.WRITE, getTargetIdList(null)); if (file == null || documentDto == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Check that the file is orphan @@ -277,7 +267,7 @@ public class FileResource extends BaseResource { // Get the document DocumentDao documentDao = new DocumentDao(); if (documentDao.getDocument(documentId, PermType.WRITE, getTargetIdList(null)) == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Reorder files @@ -313,7 +303,7 @@ public class FileResource extends BaseResource { if (documentId != null) { AclDao aclDao = new AclDao(); if (!aclDao.checkPermission(documentId, PermType.READ, getTargetIdList(shareId))) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } } else if (!authenticated) { throw new ForbiddenClientException(); @@ -360,7 +350,7 @@ public class FileResource extends BaseResource { DocumentDao documentDao = new DocumentDao(); File file = fileDao.getFile(id); if (file == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } DocumentDto documentDto = null; @@ -371,7 +361,7 @@ public class FileResource extends BaseResource { throw new ForbiddenClientException(); } } else if ((documentDto = documentDao.getDocument(file.getDocumentId(), PermType.WRITE, getTargetIdList(null))) == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Delete the file @@ -433,7 +423,7 @@ public class FileResource extends BaseResource { UserDao userDao = new UserDao(); File file = fileDao.getFile(fileId); if (file == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } if (file.getDocumentId() == null) { @@ -454,7 +444,7 @@ public class FileResource extends BaseResource { // Get the stored file java.nio.file.Path storedFile; String mimeType; - boolean decrypt = false; + boolean decrypt; if (size != null) { storedFile = DirectoryUtil.getStorageDirectory().resolve(fileId + "_" + size); mimeType = MimeType.IMAGE_JPEG; // Thumbnails are JPEG @@ -488,8 +478,12 @@ public class FileResource extends BaseResource { try { ByteStreams.copy(responseInputStream, outputStream); } finally { - responseInputStream.close(); - outputStream.close(); + try { + responseInputStream.close(); + outputStream.close(); + } catch (IOException e) { + // Ignore + } } } }; @@ -521,7 +515,7 @@ public class FileResource extends BaseResource { DocumentDao documentDao = new DocumentDao(); DocumentDto documentDto = documentDao.getDocument(documentId, PermType.READ, getTargetIdList(shareId)); if (documentDto == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Get files and user associated with this document diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/GroupResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/GroupResource.java index 8cf8c07c..d345ee97 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/GroupResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/GroupResource.java @@ -1,22 +1,5 @@ package com.sismics.docs.rest.resource; -import java.text.MessageFormat; -import java.util.List; - -import javax.json.Json; -import javax.json.JsonArrayBuilder; -import javax.json.JsonObjectBuilder; -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; - import com.google.common.base.Strings; import com.sismics.docs.core.dao.jpa.GroupDao; import com.sismics.docs.core.dao.jpa.UserDao; @@ -34,6 +17,14 @@ import com.sismics.rest.exception.ForbiddenClientException; import com.sismics.rest.util.JsonUtil; import com.sismics.rest.util.ValidationUtil; +import javax.json.Json; +import javax.json.JsonArrayBuilder; +import javax.json.JsonObjectBuilder; +import javax.ws.rs.*; +import javax.ws.rs.core.Response; +import java.text.MessageFormat; +import java.util.List; + /** * Group REST resources. * @@ -109,12 +100,12 @@ public class GroupResource extends BaseResource { GroupDao groupDao = new GroupDao(); Group group = groupDao.getActiveByName(groupName); if (group == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Avoid duplicates Group existingGroup = groupDao.getActiveByName(name); - if (existingGroup != null && existingGroup.getId() != group.getId()) { + if (existingGroup != null && !existingGroup.getId().equals(group.getId())) { throw new ClientException("GroupAlreadyExists", MessageFormat.format("This group already exists: {0}", name)); } @@ -155,7 +146,7 @@ public class GroupResource extends BaseResource { GroupDao groupDao = new GroupDao(); Group group = groupDao.getActiveByName(groupName); if (group == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Delete the group @@ -191,14 +182,14 @@ public class GroupResource extends BaseResource { GroupDao groupDao = new GroupDao(); Group group = groupDao.getActiveByName(groupName); if (group == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Get the user UserDao userDao = new UserDao(); User user = userDao.getActiveByUsername(username); if (user == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Avoid duplicates @@ -248,14 +239,14 @@ public class GroupResource extends BaseResource { GroupDao groupDao = new GroupDao(); Group group = groupDao.getActiveByName(groupName); if (group == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Get the user UserDao userDao = new UserDao(); User user = userDao.getActiveByUsername(username); if (user == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Remove the membership @@ -315,7 +306,7 @@ public class GroupResource extends BaseResource { GroupDao groupDao = new GroupDao(); Group group = groupDao.getActiveByName(groupName); if (group == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Build the response diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/ShareResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/ShareResource.java index 93957469..f51d2214 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/ShareResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/ShareResource.java @@ -1,19 +1,6 @@ package com.sismics.docs.rest.resource; -import java.text.MessageFormat; -import java.util.List; - -import javax.json.Json; -import javax.json.JsonObjectBuilder; -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; - import com.sismics.docs.core.constant.AclTargetType; import com.sismics.docs.core.constant.PermType; import com.sismics.docs.core.dao.jpa.AclDao; @@ -26,6 +13,13 @@ import com.sismics.rest.exception.ForbiddenClientException; import com.sismics.rest.util.JsonUtil; import com.sismics.rest.util.ValidationUtil; +import javax.json.Json; +import javax.json.JsonObjectBuilder; +import javax.ws.rs.*; +import javax.ws.rs.core.Response; +import java.text.MessageFormat; +import java.util.List; + /** * Share REST resources. * @@ -55,7 +49,7 @@ public class ShareResource extends BaseResource { // Get the document DocumentDao documentDao = new DocumentDao(); if (documentDao.getDocument(documentId, PermType.WRITE, getTargetIdList(null)) == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Create the share diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/TagResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/TagResource.java index 9891b816..11eab035 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/TagResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/TagResource.java @@ -6,13 +6,7 @@ import java.util.List; import javax.json.Json; import javax.json.JsonArrayBuilder; import javax.json.JsonObjectBuilder; -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; +import javax.ws.rs.*; import javax.ws.rs.core.Response; import com.sismics.docs.core.constant.PermType; @@ -20,6 +14,7 @@ import com.sismics.docs.core.dao.jpa.AclDao; import com.sismics.docs.core.dao.jpa.criteria.TagCriteria; import com.sismics.docs.core.dao.jpa.dto.TagDto; import com.sismics.docs.core.model.jpa.Acl; +import com.sismics.docs.core.util.jpa.SortCriteria; import org.apache.commons.lang.StringUtils; import com.sismics.docs.core.dao.jpa.TagDao; @@ -50,7 +45,7 @@ public class TagResource extends BaseResource { } TagDao tagDao = new TagDao(); - List tagDtoList = tagDao.findByCriteria(new TagCriteria().setTargetIdList(getTargetIdList(null)), null); + List tagDtoList = tagDao.findByCriteria(new TagCriteria().setTargetIdList(getTargetIdList(null)), new SortCriteria(1, true)); JsonArrayBuilder items = Json.createArrayBuilder(); for (TagDto tagDto : tagDtoList) { items.add(Json.createObjectBuilder() @@ -121,18 +116,17 @@ public class TagResource extends BaseResource { } // Check the parent - TagDao tagDao = new TagDao(); if (StringUtils.isEmpty(parentId)) { parentId = null; } else { - List tagDtoList = tagDao.findByCriteria(new TagCriteria().setTargetIdList(getTargetIdList(null)).setId(parentId), null); - if (tagDtoList.size() == 0) { + AclDao aclDao = new AclDao(); + if (!aclDao.checkPermission(parentId, PermType.READ, getTargetIdList(null))) { throw new ClientException("ParentNotFound", MessageFormat.format("Parent not found: {0}", parentId)); } - parentId = tagDtoList.get(0).getId(); } // Create the tag + TagDao tagDao = new TagDao(); Tag tag = new Tag(); tag.setName(name); tag.setColor(color); @@ -188,25 +182,23 @@ public class TagResource extends BaseResource { throw new ClientException("SpacesNotAllowed", "Spaces are not allowed in tag name"); } - // Get the tag - TagDao tagDao = new TagDao(); - List tagDtoList = tagDao.findByCriteria(new TagCriteria().setTargetIdList(getTargetIdList(null)).setId(id), null); - if (tagDtoList.size() == 0) { - throw new ClientException("TagNotFound", MessageFormat.format("Tag not found: {0}", id)); + // Check permission + AclDao aclDao = new AclDao(); + if (!aclDao.checkPermission(id, PermType.WRITE, getTargetIdList(null))) { + throw new NotFoundException(); } // Check the parent if (StringUtils.isEmpty(parentId)) { parentId = null; } else { - tagDtoList = tagDao.findByCriteria(new TagCriteria().setTargetIdList(getTargetIdList(null)).setId(parentId), null); - if (tagDtoList.size() == 0) { + if (!aclDao.checkPermission(parentId, PermType.READ, getTargetIdList(null))) { throw new ClientException("ParentNotFound", MessageFormat.format("Parent not found: {0}", parentId)); } - parentId = tagDtoList.get(0).getId(); } // Update the tag + TagDao tagDao = new TagDao(); Tag tag = tagDao.getById(id); if (!StringUtils.isEmpty(name)) { tag.setName(name); @@ -239,13 +231,13 @@ public class TagResource extends BaseResource { } // Get the tag - TagDao tagDao = new TagDao(); - List tagDtoList = tagDao.findByCriteria(new TagCriteria().setTargetIdList(getTargetIdList(null)).setId(id), null); - if (tagDtoList.size() == 0) { - throw new ClientException("TagNotFound", MessageFormat.format("Tag not found: {0}", id)); + AclDao aclDao = new AclDao(); + if (!aclDao.checkPermission(id, PermType.WRITE, getTargetIdList(null))) { + throw new NotFoundException(); } // Delete the tag + TagDao tagDao = new TagDao(); tagDao.delete(id, principal.getId()); // Always return OK diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/VocabularyResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/VocabularyResource.java index 479d86d2..06ba5ee8 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/VocabularyResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/VocabularyResource.java @@ -1,26 +1,18 @@ package com.sismics.docs.rest.resource; -import java.util.List; - -import javax.json.Json; -import javax.json.JsonArrayBuilder; -import javax.json.JsonObjectBuilder; -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; - import com.sismics.docs.core.dao.jpa.VocabularyDao; import com.sismics.docs.core.model.jpa.Vocabulary; import com.sismics.docs.rest.constant.BaseFunction; import com.sismics.rest.exception.ForbiddenClientException; import com.sismics.rest.util.ValidationUtil; +import javax.json.Json; +import javax.json.JsonArrayBuilder; +import javax.json.JsonObjectBuilder; +import javax.ws.rs.*; +import javax.ws.rs.core.Response; +import java.util.List; + /** * Vocabulary REST resources. * @@ -58,7 +50,7 @@ public class VocabularyResource extends BaseResource { * * @param name Name * @param value Value - * @param order Order + * @param orderStr Order * @return Response */ @PUT @@ -95,10 +87,11 @@ public class VocabularyResource extends BaseResource { /** * Update a vocabulary. - * + * + * @param id ID * @param name Name * @param value Value - * @param order Order + * @param orderStr Order * @return Response */ @POST @@ -127,7 +120,7 @@ public class VocabularyResource extends BaseResource { VocabularyDao vocabularyDao = new VocabularyDao(); Vocabulary vocabulary = vocabularyDao.getById(id); if (vocabulary == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Update the vocabulary @@ -169,7 +162,7 @@ public class VocabularyResource extends BaseResource { VocabularyDao vocabularyDao = new VocabularyDao(); Vocabulary vocabulary = vocabularyDao.getById(id); if (vocabulary == null) { - return Response.status(Status.NOT_FOUND).build(); + throw new NotFoundException(); } // Delete the vocabulary diff --git a/docs-web/src/test/java/com/sismics/docs/rest/TestAclResource.java b/docs-web/src/test/java/com/sismics/docs/rest/TestAclResource.java index 35cf277f..8b2440e3 100644 --- a/docs-web/src/test/java/com/sismics/docs/rest/TestAclResource.java +++ b/docs-web/src/test/java/com/sismics/docs/rest/TestAclResource.java @@ -249,4 +249,149 @@ public class TestAclResource extends BaseJerseyTest { groups = json.getJsonArray("groups"); Assert.assertEquals(1, groups.size()); } + + @Test + public void testAclTags() { + // Login acltag1 + clientUtil.createUser("acltag1"); + String acltag1Token = clientUtil.login("acltag1"); + + // Login acltag2 + clientUtil.createUser("acltag2"); + String acltag2Token = clientUtil.login("acltag2"); + + // Create tag1 with acltag1 + JsonObject json = target().path("/tag").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag1Token) + .put(Entity.form(new Form() + .param("name", "AclTag1") + .param("color", "#ff0000")), JsonObject.class); + String tag1Id = json.getString("id"); + Assert.assertNotNull(tag1Id); + + // Create document1 with acltag1 tagged with tag1 + json = target().path("/document").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag1Token) + .put(Entity.form(new Form() + .param("title", "My super document 1") + .param("tags", tag1Id) + .param("language", "eng")), JsonObject.class); + String document1Id = json.getString("id"); + + // acltag2 cannot see document1 + Response response = target().path("/document/" + document1Id).request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token) + .get(); + Assert.assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus()); + + // acltag2 cannot see any tag + json = target().path("/tag/list").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token) + .get(JsonObject.class); + JsonArray tags = json.getJsonArray("tags"); + Assert.assertEquals(0, tags.size()); + + // acltag2 cannot see any document + json = target().path("/document/list") + .queryParam("sort_column", 3) + .queryParam("asc", true) + .request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token) + .get(JsonObject.class); + JsonArray documents = json.getJsonArray("documents"); + Assert.assertEquals(0, documents.size()); + + // acltag2 cannot edit tag1 + response = target().path("/tag/" + tag1Id).request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token) + .post(Entity.form(new Form() + .param("name", "AclTag1") + .param("color", "#ff0000"))); + Assert.assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus()); + + // acltag2 cannot edit document1 + response = target().path("/document/" + document1Id).request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token) + .post(Entity.form(new Form() + .param("title", "My super document 1") + .param("tags", tag1Id) + .param("language", "eng"))); + Assert.assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus()); + + // Add an ACL READ for acltag2 with acltag1 on tag1 + target().path("/acl").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag1Token) + .put(Entity.form(new Form() + .param("source", tag1Id) + .param("perm", "READ") + .param("target", "acltag2") + .param("type", "USER")), JsonObject.class); + + // acltag2 still cannot edit tag1 + response = target().path("/tag/" + tag1Id).request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token) + .post(Entity.form(new Form() + .param("name", "AclTag1") + .param("color", "#ff0000"))); + Assert.assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus()); + + // acltag2 still cannot edit document1 + response = target().path("/document/" + document1Id).request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token) + .post(Entity.form(new Form() + .param("title", "My super document 1") + .param("tags", tag1Id) + .param("language", "eng"))); + Assert.assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus()); + + // acltag2 can see document1 with tag1 + json = target().path("/document/" + document1Id).request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token) + .get(JsonObject.class); + tags = json.getJsonArray("tags"); + Assert.assertEquals(1, tags.size()); + Assert.assertEquals(tag1Id, tags.getJsonObject(0).getString("id")); + + // acltag2 can see tag1 + json = target().path("/tag/list").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token) + .get(JsonObject.class); + tags = json.getJsonArray("tags"); + Assert.assertEquals(1, tags.size()); + Assert.assertEquals(tag1Id, tags.getJsonObject(0).getString("id")); + + // acltag2 can see exactly one document + json = target().path("/document/list") + .queryParam("sort_column", 3) + .queryParam("asc", true) + .request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token) + .get(JsonObject.class); + documents = json.getJsonArray("documents"); + Assert.assertEquals(1, documents.size()); + + // Add an ACL WRITE for acltag2 with acltag1 on tag1 + target().path("/acl").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag1Token) + .put(Entity.form(new Form() + .param("source", tag1Id) + .param("perm", "WRITE") + .param("target", "acltag2") + .param("type", "USER")), JsonObject.class); + + // acltag2 can edit tag1 + target().path("/tag/" + tag1Id).request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token) + .post(Entity.form(new Form() + .param("name", "AclTag1") + .param("color", "#ff0000")), JsonObject.class); + + // acltag2 can edit document1 + target().path("/document/" + document1Id).request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token) + .post(Entity.form(new Form() + .param("title", "My super document 1") + .param("tags", tag1Id) + .param("language", "eng")), JsonObject.class); + } } \ No newline at end of file