Skip to content

Commit

Permalink
Download all files from a document as ZIP
Browse files Browse the repository at this point in the history
  • Loading branch information
jendib committed Feb 23, 2014
1 parent ae56601 commit 34e3ac5
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 3 deletions.
25 changes: 25 additions & 0 deletions docs-core/src/main/java/com/sismics/util/mime/MimeTypeUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,29 @@ public static String guessMimeType(byte[] headerBytes) throws UnsupportedEncodin

return null;
}

/**
* Get a file extension linked to a MIME type.
*
* @param mimeType MIME type
* @return File extension
*/
public static String getFileExtension(String mimeType) {
switch (mimeType) {
case MimeType.APPLICATION_ZIP:
return "zip";
case MimeType.IMAGE_GIF:
return "gif";
case MimeType.IMAGE_JPEG:
return "jpg";
case MimeType.IMAGE_PNG:
return "png";
case MimeType.IMAGE_X_ICON:
return "ico";
case MimeType.APPLICATION_PDF:
return "pdf";
default:
return null;
}
}
}
1 change: 0 additions & 1 deletion docs-parent/TODO
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
- Automatic backup system using Quartz (server)
- Handle error while uploading a file
- Download all files as zip (docs & share)
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.persistence.NoResultException;
import javax.ws.rs.Consumes;
Expand Down Expand Up @@ -372,4 +374,75 @@ public void write(OutputStream outputStream) throws IOException, WebApplicationE
.header("Expires", new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z").format(new Date().getTime() + 3600000 * 24))
.build();
}

/**
* Returns all files from a document, zipped.
*
* @param documentId Document ID
* @return Response
* @throws JSONException
*/
@GET
@Path("zip")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response zip(
@QueryParam("id") String documentId,
@QueryParam("share") String shareId) throws JSONException {
authenticate();

// Get the document
DocumentDao documentDao = new DocumentDao();
Document document;
try {
document = documentDao.getDocument(documentId);

// Check document visibility
ShareDao shareDao = new ShareDao();
if (!shareDao.checkVisibility(document, principal.getId(), shareId)) {
throw new ForbiddenClientException();
}
} catch (NoResultException e) {
throw new ClientException("DocumentNotFound", MessageFormat.format("Document not found: {0}", documentId));
}

// Get files and user associated with this document
FileDao fileDao = new FileDao();
UserDao userDao = new UserDao();
final List<File> fileList = fileDao.getByDocumentId(documentId);
final User user = userDao.getById(document.getUserId());

// Create the ZIP stream
StreamingOutput stream = new StreamingOutput() {
@Override
public void write(OutputStream outputStream) throws IOException, WebApplicationException {
try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
// Add each file to the ZIP stream
int index = 0;
for (File file : fileList) {
java.io.File storedfile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file.getId()).toFile();
InputStream fileInputStream = new FileInputStream(storedfile);

// Add the decrypted file to the ZIP stream
try (InputStream decryptedStream = EncryptionUtil.decryptInputStream(fileInputStream, user.getPrivateKey())) {
ZipEntry zipEntry = new ZipEntry(index + "." + MimeTypeUtil.getFileExtension(file.getMimeType()));
zipOutputStream.putNextEntry(zipEntry);
ByteStreams.copy(decryptedStream, zipOutputStream);
zipOutputStream.closeEntry();
} catch (Exception e) {
e.printStackTrace();
throw new WebApplicationException(e);
}
index++;
}
}
outputStream.close();
}
};

// Write to the output
return Response.ok(stream)
.header("Content-Type", "application/zip")
.header("Content-Disposition", "attachment; filename=\"" + document.getTitle().replaceAll("\\W+", "_") + ".zip\"")
.build();
}
}
8 changes: 7 additions & 1 deletion docs-web/src/main/webapp/src/partial/docs/document.view.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@
</div>

<div class="page-header">
<h1>{{ document.title }} <small>{{ document.create_date | date: 'yyyy-MM-dd' }}</small> <img ng-if="document" ng-src="img/flag/{{ document.language }}.png" title="{{ document.language }}" /></h1>
<h1>
{{ document.title }} <small>{{ document.create_date | date: 'yyyy-MM-dd' }}</small>
<img ng-if="document" ng-src="img/flag/{{ document.language }}.png" title="{{ document.language }}" />
<a ng-href="../api/file/zip?id={{ document.id }}" class="btn btn-default" title="Download all files">
<span class="glyphicon glyphicon-compressed"></span>
</a>
</h1>
<p>
<button class="btn btn-sm btn-info" ng-click="share()">
<span class="glyphicon glyphicon-share"></span> Share
Expand Down
7 changes: 6 additions & 1 deletion docs-web/src/main/webapp/src/partial/share/share.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
<div class="row">
<div class="well col-md-12">
<div class="page-header">
<h1>{{ document.title }} <small>{{ document.create_date | date: 'yyyy-MM-dd' }}</small></h1>
<h1>
{{ document.title }} <small>{{ document.create_date | date: 'yyyy-MM-dd' }}</small>
<a ng-href="../api/file/zip?id={{ document.id }}&share={{ $stateParams.shareId }}" class="btn btn-default" title="Download all files">
<span class="glyphicon glyphicon-compressed"></span>
</a>
</h1>
<ul class="list-inline">
<li ng-repeat="tag in document.tags"><span class="label label-info" ng-style="{ 'background': tag.color }">{{ tag.name }}</span></li>
</ul>
Expand Down
10 changes: 10 additions & 0 deletions docs-web/src/test/java/com/sismics/docs/rest/TestFileResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,16 @@ public void testFileResource() throws Exception {
Assert.assertEquals(file2Id, files.getJSONObject(0).getString("id"));
Assert.assertEquals(file1Id, files.getJSONObject(1).getString("id"));

// Get a ZIP from all files
fileResource = resource().path("/file/zip");
fileResource.addFilter(new CookieAuthenticationFilter(file1AuthenticationToken));
getParams = new MultivaluedMapImpl();
getParams.putSingle("id", document1Id);
response = fileResource.queryParams(getParams).get(ClientResponse.class);
is = response.getEntityInputStream();
fileBytes = ByteStreams.toByteArray(is);
Assert.assertEquals(MimeType.APPLICATION_ZIP, MimeTypeUtil.guessMimeType(fileBytes));

// Deletes a file
fileResource = resource().path("/file/" + file1Id);
fileResource.addFilter(new CookieAuthenticationFilter(file1AuthenticationToken));
Expand Down

0 comments on commit 34e3ac5

Please sign in to comment.