#55: Export document in PDF (REST resource + export options UI)

This commit is contained in:
jendib 2016-01-01 01:56:54 +01:00
parent 25a17ae2da
commit 2c791f5123
4 changed files with 111 additions and 16 deletions

View File

@ -1,5 +1,8 @@
package com.sismics.docs.rest.resource; package com.sismics.docs.rest.resource;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
@ -19,8 +22,10 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.StreamingOutput;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@ -31,12 +36,14 @@ import org.joda.time.format.DateTimeParser;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.Strings; 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.Constants;
import com.sismics.docs.core.constant.PermType; import com.sismics.docs.core.constant.PermType;
import com.sismics.docs.core.dao.jpa.AclDao; import com.sismics.docs.core.dao.jpa.AclDao;
import com.sismics.docs.core.dao.jpa.DocumentDao; import com.sismics.docs.core.dao.jpa.DocumentDao;
import com.sismics.docs.core.dao.jpa.FileDao; import com.sismics.docs.core.dao.jpa.FileDao;
import com.sismics.docs.core.dao.jpa.TagDao; import com.sismics.docs.core.dao.jpa.TagDao;
import com.sismics.docs.core.dao.jpa.UserDao;
import com.sismics.docs.core.dao.jpa.criteria.DocumentCriteria; 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.AclDto;
import com.sismics.docs.core.dao.jpa.dto.DocumentDto; import com.sismics.docs.core.dao.jpa.dto.DocumentDto;
@ -50,6 +57,8 @@ import com.sismics.docs.core.model.jpa.Acl;
import com.sismics.docs.core.model.jpa.Document; import com.sismics.docs.core.model.jpa.Document;
import com.sismics.docs.core.model.jpa.File; import com.sismics.docs.core.model.jpa.File;
import com.sismics.docs.core.model.jpa.Tag; 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; import com.sismics.docs.core.util.jpa.PaginatedList;
import com.sismics.docs.core.util.jpa.PaginatedLists; import com.sismics.docs.core.util.jpa.PaginatedLists;
import com.sismics.docs.core.util.jpa.SortCriteria; import com.sismics.docs.core.util.jpa.SortCriteria;
@ -58,6 +67,7 @@ import com.sismics.rest.exception.ForbiddenClientException;
import com.sismics.rest.exception.ServerException; import com.sismics.rest.exception.ServerException;
import com.sismics.rest.util.JsonUtil; import com.sismics.rest.util.JsonUtil;
import com.sismics.rest.util.ValidationUtil; import com.sismics.rest.util.ValidationUtil;
import com.sismics.util.mime.MimeType;
/** /**
* Document REST resources. * Document REST resources.
@ -145,6 +155,64 @@ public class DocumentResource extends BaseResource {
return Response.ok().entity(document.build()).build(); return Response.ok().entity(document.build()).build();
} }
/**
* Export a document to PDF.
*
* @param documentId Document ID
* @return Response
*/
@GET
@Path("{id: [a-z0-9\\-]+}/pdf")
public Response getPdf(
@PathParam("id") String documentId,
@QueryParam("share") String shareId,
@QueryParam("metadata") Boolean metadata,
@QueryParam("comments") Boolean comments,
final @QueryParam("fitimagetopage") Boolean fitImageToPage,
@QueryParam("margin") String marginStr) {
authenticate();
// Validate input
final int margin = ValidationUtil.validateInteger(marginStr, "margin");
// Get document and check read permission
DocumentDao documentDao = new DocumentDao();
Document document = documentDao.getDocument(documentId, PermType.READ, shareId == null ? principal.getId() : shareId);
if (document == null) {
return Response.status(Status.NOT_FOUND).build();
}
// Get files
FileDao fileDao = new FileDao();
UserDao userDao = new UserDao();
final List<File> fileList = fileDao.getByDocumentId(null, documentId);
for (File file : fileList) {
// A file is always encrypted by the creator of it
// Store its private key to decrypt it
User user = userDao.getById(file.getUserId());
file.setPrivateKey(user.getPrivateKey());
}
// Convert to PDF
StreamingOutput stream = new StreamingOutput() {
@Override
public void write(OutputStream outputStream) throws IOException, WebApplicationException {
try (InputStream inputStream = PdfUtil.convertToPdf(fileList, fitImageToPage, margin)) {
ByteStreams.copy(inputStream, outputStream);
} catch (Exception e) {
throw new IOException(e);
} finally {
outputStream.close();
}
}
};
return Response.ok(stream)
.header("Content-Type", MimeType.APPLICATION_PDF)
.header("Content-Disposition", "inline; filename=\"" + document.getTitle() + ".pdf\"")
.build();
}
/** /**
* Returns all documents. * Returns all documents.
* *

View File

@ -7,7 +7,8 @@ angular.module('docs').controller('DocumentModalPdf', function ($scope, $window,
$scope.export = { $scope.export = {
metadata: false, metadata: false,
comments: false, comments: false,
fitimagetopage: false fitimagetopage: true,
margin: 10
}; };
// Export to PDF // Export to PDF
@ -15,7 +16,8 @@ angular.module('docs').controller('DocumentModalPdf', function ($scope, $window,
$window.open('../api/document/' + $stateParams.id $window.open('../api/document/' + $stateParams.id
+ '/pdf?metadata=' + $scope.export.metadata + '/pdf?metadata=' + $scope.export.metadata
+ '&comments=' + $scope.export.comments + '&comments=' + $scope.export.comments
+ '&fitimagetopage=' + $scope.export.fitimagetopage); + '&fitimagetopage=' + $scope.export.fitimagetopage
+ '&margin=' + $scope.export.margin);
$modalInstance.close(); $modalInstance.close();
}; };

View File

@ -2,22 +2,39 @@
<h3>Export to PDF</h3> <h3>Export to PDF</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form> <form class="form-horizontal">
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" ng-model="export.metadata" /> Export metadata <input type="checkbox" ng-model="export.metadata" /> Export metadata
</label> </label>
</div> </div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" ng-model="export.comments" /> Export comments <input type="checkbox" ng-model="export.comments" /> Export comments
</label> </label>
</div> </div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" ng-model="export.fitimagetopage" /> Fit image to page <input type="checkbox" ng-model="export.fitimagetopage" /> Fit image to page
</label> </label>
</div> </div>
</div>
</div>
<label for="inputMargin" class="col-sm-2 control-label">Margin</label>
<div class="input-group col-sm-5">
<input type="number" class="form-control" id="inputMargin" ng-model="export.margin" min="0" max="100" step="1">
<div class="input-group-addon">mm</div>
</div>
</form> </form>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">

View File

@ -196,6 +196,14 @@ public class TestDocumentResource extends BaseJerseyTest {
Assert.assertEquals(1, tags.size()); Assert.assertEquals(1, tags.size());
Assert.assertEquals(tag1Id, tags.getJsonObject(0).getString("id")); Assert.assertEquals(tag1Id, tags.getJsonObject(0).getString("id"));
// Export a document in PDF format
Response response = target().path("/document/" + document1Id).request()
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token)
.get();
InputStream is = (InputStream) response.getEntity();
byte[] pdfBytes = ByteStreams.toByteArray(is);
Assert.assertTrue(pdfBytes.length > 0);
// Create a tag // Create a tag
json = target().path("/tag").request() json = target().path("/tag").request()
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token) .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token)
@ -244,7 +252,7 @@ public class TestDocumentResource extends BaseJerseyTest {
Assert.assertFalse(thumbnailFile.exists()); Assert.assertFalse(thumbnailFile.exists());
// Get a document (KO) // Get a document (KO)
Response response = target().path("/document/" + document1Id).request() response = target().path("/document/" + document1Id).request()
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token) .cookie(TokenBasedSecurityFilter.COOKIE_NAME, document1Token)
.get(); .get();
Assert.assertEquals(Status.NOT_FOUND, Status.fromStatusCode(response.getStatus())); Assert.assertEquals(Status.NOT_FOUND, Status.fromStatusCode(response.getStatus()));