Merge pull request #46 from sismics/master

Push to production
This commit is contained in:
Benjamin Gamard 2015-11-21 20:32:16 +01:00
commit f98a12b96f
18 changed files with 128 additions and 36 deletions

View File

@ -90,7 +90,7 @@ public class CommentDao {
*/
public List<CommentDto> getByDocumentId(String documentId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
StringBuilder sb = new StringBuilder("select c.COM_ID_C, c.COM_CONTENT_C, c.COM_CREATEDATE_D, u.USE_USERNAME_C from T_COMMENT c, T_USER u");
StringBuilder sb = new StringBuilder("select c.COM_ID_C, c.COM_CONTENT_C, c.COM_CREATEDATE_D, u.USE_USERNAME_C, u.USE_EMAIL_C from T_COMMENT c, T_USER u");
sb.append(" where c.COM_IDDOC_C = :documentId and c.COM_IDUSER_C = u.USE_ID_C and c.COM_DELETEDATE_D is null ");
sb.append(" order by c.COM_CREATEDATE_D asc ");
Query q = em.createNativeQuery(sb.toString());
@ -106,6 +106,7 @@ public class CommentDao {
commentDto.setContent((String) o[i++]);
commentDto.setCreateTimestamp(((Timestamp) o[i++]).getTime());
commentDto.setCreatorName((String) o[i++]);
commentDto.setCreatorEmail((String) o[i++]);
commentDtoList.add(commentDto);
}
return commentDtoList;

View File

@ -224,7 +224,7 @@ public class DocumentDao {
if (criteria.getTagIdList() != null && !criteria.getTagIdList().isEmpty()) {
int index = 0;
for (String tagId : criteria.getTagIdList()) {
sb.append(" join T_DOCUMENT_TAG dt" + index + " on dt" + index + ".DOT_IDDOCUMENT_C = d.DOC_ID_C and dt" + index + ".DOT_IDTAG_C = :tagId" + index + " ");
sb.append(" join T_DOCUMENT_TAG dt" + index + " on dt" + index + ".DOT_IDDOCUMENT_C = d.DOC_ID_C and dt" + index + ".DOT_IDTAG_C = :tagId" + index + " and dt" + index + ".DOT_DELETEDATE_D is null ");
parameterMap.put("tagId" + index, tagId);
index++;
}

View File

@ -19,6 +19,11 @@ public class CommentDto {
*/
private String creatorName;
/**
* Creator email.
*/
private String creatorEmail;
/**
* Content.
*/
@ -45,6 +50,14 @@ public class CommentDto {
this.creatorName = creatorName;
}
public String getCreatorEmail() {
return creatorEmail;
}
public void setCreatorEmail(String creatorEmail) {
this.creatorEmail = creatorEmail;
}
public String getContent() {
return content;
}

View File

@ -11,6 +11,8 @@ import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import com.sismics.util.mime.MimeType;
/**
@ -62,4 +64,21 @@ public class ImageUtil {
public static boolean isImage(String mimeType) {
return mimeType.equals(MimeType.IMAGE_GIF) || mimeType.equals(MimeType.IMAGE_PNG) || mimeType.equals(MimeType.IMAGE_JPEG);
}
/**
* Compute Gravatar hash.
* See https://en.gravatar.com/site/implement/hash/.
*
* @param email
* @return Gravatar hash
*/
public static String computeGravatar(String email) {
if (email == null) {
return null;
}
return Hashing.md5().hashString(
email.trim().toLowerCase(), Charsets.UTF_8)
.toString();
}
}

View File

@ -0,0 +1,17 @@
package com.sismics.util;
import junit.framework.Assert;
import org.junit.Test;
/**
* Test of the image utilities.
*
* @author bgamard
*/
public class TestImageUtil {
@Test
public void computeGravatarTest() throws Exception {
Assert.assertEquals("0bc83cb571cd1c50ba6f3e8a78ef1346", ImageUtil.computeGravatar("MyEmailAddress@example.com "));
}
}

View File

@ -32,7 +32,7 @@
<org.imgscalr.imgscalr-lib.version>4.2</org.imgscalr.imgscalr-lib.version>
<org.apache.pdfbox.pdfbox.version>2.0.0-RC1</org.apache.pdfbox.pdfbox.version>
<org.bouncycastle.bcprov-jdk15on.version>1.53</org.bouncycastle.bcprov-jdk15on.version>
<joda-time.joda-time.version>2.9</joda-time.joda-time.version>
<joda-time.joda-time.version>2.9.1</joda-time.joda-time.version>
<org.hibernate.hibernate.version>4.1.0.Final</org.hibernate.hibernate.version>
<javax.servlet.javax.servlet-api.version>3.1.0</javax.servlet.javax.servlet-api.version>
<com.levigo.jbig2.levigo-jbig2-imageio.version>1.6.3</com.levigo.jbig2.levigo-jbig2-imageio.version>

View File

@ -158,6 +158,9 @@ public class TokenBasedSecurityFilter implements Filter {
Set<String> baseFunctionSet = userBaseFuction.findByRoleId(user.getRoleId());
userPrincipal.setBaseFunctionSet(baseFunctionSet);
// Add email
userPrincipal.setEmail(user.getEmail());
request.setAttribute(PRINCIPAL_ATTRIBUTE, userPrincipal);
}

View File

@ -219,7 +219,6 @@
</systemProperties>
<webApp>
<contextPath>/docs-web</contextPath>
<overrideDescriptor>src/dev/main/webapp/web-override.xml</overrideDescriptor>
</webApp>
</configuration>
</plugin>

View File

@ -3,7 +3,8 @@
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
version="3.0"
metadata-complete="true">
<!-- Override init parameter to avoid nasty file locking issue on windows. -->
<servlet>

View File

@ -11,6 +11,7 @@ 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;
@ -21,6 +22,7 @@ import com.sismics.docs.core.dao.jpa.dto.CommentDto;
import com.sismics.docs.core.model.jpa.Comment;
import com.sismics.rest.exception.ForbiddenClientException;
import com.sismics.rest.util.ValidationUtil;
import com.sismics.util.ImageUtil;
/**
* Comment REST resource.
@ -64,8 +66,9 @@ public class CommentResource extends BaseResource {
// Returns the comment
JsonObjectBuilder response = Json.createObjectBuilder()
.add("id", comment.getId())
.add("creator", principal.getName())
.add("content", comment.getContent())
.add("creator", principal.getName())
.add("creator_gravatar", ImageUtil.computeGravatar(principal.getEmail()))
.add("create_date", comment.getCreateDate().getTime());
return Response.ok().entity(response.build()).build();
}
@ -119,14 +122,13 @@ public class CommentResource extends BaseResource {
*/
@GET
@Path("{documentId: [a-z0-9\\-]+}")
public Response get(@PathParam("documentId") String documentId) {
if (!authenticate()) {
throw new ForbiddenClientException();
}
public Response get(@PathParam("documentId") String documentId,
@QueryParam("share") String shareId) {
authenticate();
// Read access on doc gives access to read comments
DocumentDao documentDao = new DocumentDao();
if (documentDao.getDocument(documentId, PermType.READ, principal.getId()) == null) {
if (documentDao.getDocument(documentId, PermType.READ, shareId == null ? principal.getId() : shareId) == null) {
return Response.status(Status.NOT_FOUND).build();
}
@ -139,6 +141,7 @@ public class CommentResource extends BaseResource {
.add("id", commentDto.getId())
.add("content", commentDto.getContent())
.add("creator", commentDto.getCreatorName())
.add("creator_gravatar", ImageUtil.computeGravatar(commentDto.getCreatorEmail()))
.add("create_date", commentDto.getCreateTimestamp()));
}

View File

@ -3,7 +3,8 @@
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
version="3.0"
metadata-complete="true">
<display-name>Docs</display-name>
<!-- This filter is used to process a couple things in the request context -->
@ -55,4 +56,6 @@
<servlet-name>JerseyServlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
<absolute-ordering/>
</web-app>

View File

@ -20,6 +20,13 @@ angular.module('share').controller('Share', function($scope, $state, $stateParam
$scope.files = data.files;
});
// Load comments from server
Restangular.one('comment', $stateParams.documentId).get({ share: $stateParams.shareId }).then(function(data) {
$scope.comments = data.comments;
}, function(response) {
$scope.commentsError = response;
});
/**
* Navigate to the selected file.
*/

View File

@ -15,7 +15,8 @@
<a ng-href="#/document/view/{{ log.target }}">{{ log.message }}</a>
</span>
<span ng-switch-when="File">
<a ng-href="#/document/view/{{ log.message }}/content/file/{{ log.target }}">Open</a>
<a ng-if="log.message" ng-href="#/document/view/{{ log.message }}/content/file/{{ log.target }}">Open</a>
<a ng-if="!log.message" ng-href="#/document/file/{{ log.target }}">Open</a>
</span>
<span ng-switch-when="Comment">
<a ng-href="#/document/view/{{ log.message }}">See</a>

View File

@ -72,15 +72,20 @@
<p ng-show="!comments && commentsError">Error loading comments</p>
</div>
<div ng-repeat="comment in comments" style="overflow: hidden">
<strong>{{ comment.creator }}</strong>
<p>
{{ comment.content }}<br />
<span class="text-muted">{{ comment.create_date | date: 'yyyy-MM-dd' }}</span>
<div ng-repeat="comment in comments" class="media" style="overflow: hidden">
<div class="pull-left">
<img ng-src="http://www.gravatar.com/avatar/{{ comment.creator_gravatar }}?s=40&d=identicon" class="media-object" />
</div>
<div class="media-body">
<strong>{{ comment.creator }}</strong>
<p>
{{ comment.content }}<br />
<span class="text-muted">{{ comment.create_date | date: 'yyyy-MM-dd' }}</span>
<span class="text-muted pull-right btn-link"
ng-show="document.writable || userInfo.username == comment.creator"
ng-click="deleteComment(comment)">Delete</span>
</p>
</p>
</div>
</div>
<form ng-submit="addComment()">

View File

@ -1,5 +1,5 @@
<div class="row">
<div class="well col-md-12">
<div class="col-md-10">
<div class="page-header">
<h1>
{{ document.title }} <small>{{ document.create_date | date: 'yyyy-MM-dd' }}</small>
@ -26,4 +26,31 @@
<div ui-view="file"></div>
</div>
<div class="col-md-2">
<p class="page-header">
<span class="glyphicon glyphicon-comment"></span>
Comments
</p>
<div ng-show="!comments || comments.length == 0" class="text-center text-muted">
<h1 class="glyphicon glyphicon-comment"></h1>
<p ng-show="!comments && !commentsError">Loading...</p>
<p ng-show="comments.length == 0">No comments on this document yet</p>
<p ng-show="!comments && commentsError">Error loading comments</p>
</div>
<div ng-repeat="comment in comments" class="media" style="overflow: hidden">
<div class="pull-left">
<img ng-src="http://www.gravatar.com/avatar/{{ comment.creator_gravatar }}?s=40&d=identicon" class="media-object" />
</div>
<div class="media-body">
<strong>{{ comment.creator }}</strong>
<p>
{{ comment.content }}<br />
<span class="text-muted">{{ comment.create_date | date: 'yyyy-MM-dd' }}</span>
</p>
</div>
</div>
</div>
</div>

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="docs"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- Override init parameter to avoid nasty file locking issue on windows. -->
<servlet>
<servlet-name>default</servlet-name>
<init-param>
<param-name>useFileMappedBuffer</param-name>
<param-value>false</param-value>
</init-param>
</servlet>
</web-app>

View File

@ -127,6 +127,7 @@ public class TestCommentResource extends BaseJerseyTest {
Assert.assertEquals(comment2Id, comment.getString("id"));
Assert.assertEquals("Comment by comment2", comment.getString("content"));
Assert.assertEquals("comment2", comment.getString("creator"));
Assert.assertEquals("d6e56c42f61983bba80d370138763420", comment.getString("creator_gravatar"));
Assert.assertNotNull(comment.getJsonNumber("create_date"));
// Delete a comment with comment2

View File

@ -78,6 +78,14 @@ public class TestShareResource extends BaseJerseyTest {
Assert.assertEquals(document1Id, json.getString("id"));
Assert.assertEquals(3, json.getJsonArray("acls").size()); // 2 for the creator, 1 for the share
// Get all comments from this document anonymously
json = target().path("/comment/" + document1Id)
.queryParam("share", share1Id)
.request()
.get(JsonObject.class);
JsonArray comments = json.getJsonArray("comments");
Assert.assertEquals(0, comments.size());
// Get all files from this document anonymously
json = target().path("/file/list")
.queryParam("id", document1Id)