From d61e33e6e112853da69f46e44ae39c25fd2ff629 Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Fri, 31 Oct 2014 14:15:46 +0100 Subject: [PATCH] OO-1283: download as zip in folders --- .../bc/_i18n/LocalStrings_de.properties | 1 + .../bc/_i18n/LocalStrings_en.properties | 1 + .../bc/_i18n/LocalStrings_fr.properties | 1 + .../modules/bc/commands/CmdDownloadZip.java | 179 ++++++++++++++++++ .../bc/commands/FolderCommandFactory.java | 2 + .../components/FolderComponentRenderer.java | 6 + .../modules/bc/components/ListRenderer.java | 24 +-- 7 files changed, 200 insertions(+), 14 deletions(-) create mode 100644 src/main/java/org/olat/core/commons/modules/bc/commands/CmdDownloadZip.java diff --git a/src/main/java/org/olat/core/commons/modules/bc/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/commons/modules/bc/_i18n/LocalStrings_de.properties index f95bb83ae0d..9148c07a8bf 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/core/commons/modules/bc/_i18n/LocalStrings_de.properties @@ -95,6 +95,7 @@ del.header=L\u00F6schen best\u00E4tigen del.partial=Einige der Dateien konnten nicht gel\u00F6scht werden. dfiles=Gel\u00F6schte Dateien displayname.user=Pers\u00F6nlicher Ordner von {0} +download=Hochladen edit=Bearbeiten editQuota=Quota anpassen editQuota.nop=F\u00FCr dieses Objekt kann keine Quota gesetzt werden. diff --git a/src/main/java/org/olat/core/commons/modules/bc/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/commons/modules/bc/_i18n/LocalStrings_en.properties index 9b2057d83b8..94299cf0aa0 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/core/commons/modules/bc/_i18n/LocalStrings_en.properties @@ -94,6 +94,7 @@ del=Delete del.confirm=Do you really want to delete the following files? del.header=Confirm deletion del.partial=Some files could not be deleted. +download=Download dfiles=Deleted files displayname.user=Personal folder of {0} edit=Edit diff --git a/src/main/java/org/olat/core/commons/modules/bc/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/core/commons/modules/bc/_i18n/LocalStrings_fr.properties index 15de12ef408..11ac34d2aec 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/core/commons/modules/bc/_i18n/LocalStrings_fr.properties @@ -95,6 +95,7 @@ del.header=Confirmation de suppression del.partial=Quelques uns des fichiers n'ont pas pu \u00EAtre supprim\u00E9s. dfiles=Fichiers effac\u00E9s displayname.user=Dossier personnel de {0} +download=T\u00E9l\u00E9charger edit=Editer editQuota=Adapter les quotas editQuota.nop=Il est impossible de poser un quota pour cet objet. diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdDownloadZip.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdDownloadZip.java new file mode 100644 index 00000000000..8508c04f04a --- /dev/null +++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdDownloadZip.java @@ -0,0 +1,179 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.commons.modules.bc.commands; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.zip.ZipOutputStream; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.io.IOUtils; +import org.olat.core.commons.modules.bc.FileSelection; +import org.olat.core.commons.modules.bc.components.FolderComponent; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.media.MediaResource; +import org.olat.core.gui.translator.Translator; +import org.olat.core.logging.AssertException; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; +import org.olat.core.util.ZipUtil; +import org.olat.core.util.vfs.VFSConstants; +import org.olat.core.util.vfs.VFSContainer; +import org.olat.core.util.vfs.VFSItem; + +/** + * + * Initial date: 31.10.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class CmdDownloadZip implements FolderCommand { + + private static final OLog log = Tracing.createLoggerFor(CmdDownloadZip.class); + + private FileSelection selection; + private VFSContainer currentContainer; + private int status = FolderCommandStatus.STATUS_SUCCESS; + + + @Override + public Controller execute(FolderComponent folderComponent, UserRequest ureq, WindowControl wControl, Translator trans) { + currentContainer = folderComponent.getCurrentContainer(); + if (currentContainer.canWrite() != VFSConstants.YES) { + throw new AssertException("Cannot write to current folder."); + } + + status = FolderCommandHelper.sanityCheck(wControl, folderComponent); + if(status == FolderCommandStatus.STATUS_FAILED) { + return null; + } + + selection = new FileSelection(ureq, folderComponent.getCurrentContainerPath()); + status = FolderCommandHelper.sanityCheck3(wControl, folderComponent, selection); + if(status == FolderCommandStatus.STATUS_FAILED) { + return null; + } + + MediaResource mr = new ZipMediaResource(currentContainer, selection); + ureq.getDispatchResult().setResultingMediaResource(mr); + return null; + } + + + public int getStatus() { + return status; + } + + @Override + public boolean runsModal() { + return false; + } + + @Override + public String getModalTitle() { + return null; + } + + private static class ZipMediaResource implements MediaResource { + + private final FileSelection selection; + private final VFSContainer currentContainer; + + public ZipMediaResource(VFSContainer currentContainer, FileSelection selection) { + this.selection = selection; + this.currentContainer = currentContainer; + } + + @Override + public String getContentType() { + return "application/zip"; + } + + @Override + public Long getSize() { + return null; + } + + @Override + public InputStream getInputStream() { + return null; + } + + @Override + public Long getLastModified() { + return null; + } + + @Override + public void prepare(HttpServletResponse hres) { + List<String> selectedFiles = selection.getFiles(); + + String urlEncodedLabel; + if(selectedFiles.size() == 1) { + String filename = selectedFiles.get(0); + int lastIndexOf = filename.lastIndexOf('.'); + if(lastIndexOf > 0) { + filename = filename.substring(0, lastIndexOf); + } + urlEncodedLabel = StringHelper.urlEncodeUTF8(filename + ".zip"); + } else { + urlEncodedLabel = "Archive.zip"; + } + + hres.setHeader("Content-Disposition","attachment; filename*=UTF-8''" + urlEncodedLabel); + hres.setHeader("Content-Description", urlEncodedLabel); + + ZipOutputStream zout = null; + try { + zout = new ZipOutputStream(hres.getOutputStream()); + zout.setLevel(9); + + List<VFSItem> vfsFiles = new ArrayList<VFSItem>(); + for (String fileName : selectedFiles) { + VFSItem item = currentContainer.resolve(fileName); + if (item != null) { + vfsFiles.add(item); + } + } + + boolean success = true; + for (Iterator<VFSItem> iter = vfsFiles.iterator(); success && iter.hasNext();) { + success = ZipUtil.addToZip(iter.next(), "", zout); + } + zout.flush(); + } catch (Exception e) { + log.error("", e); + } finally { + IOUtils.closeQuietly(zout); + } + } + + @Override + public void release() { + // + } + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/FolderCommandFactory.java b/src/main/java/org/olat/core/commons/modules/bc/commands/FolderCommandFactory.java index 6b4b302247f..a4e015cf985 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/commands/FolderCommandFactory.java +++ b/src/main/java/org/olat/core/commons/modules/bc/commands/FolderCommandFactory.java @@ -54,6 +54,7 @@ public class FolderCommandFactory { public static final String COMMAND_COPY = "copy"; public static final String COMMAND_DEL = "del"; public static final String COMMAND_MAIL = "mail"; + public static final String COMMAND_DOWNLOAD_ZIP = "dzip"; public static final String COMMAND_ZIP = "zip"; public static final String COMMAND_UNZIP = "unzip"; @@ -87,6 +88,7 @@ public class FolderCommandFactory { else if (command.equals(COMMAND_MOVE)) cmd = new CmdMoveCopy(wControl, true); else if (command.equals(COMMAND_COPY)) cmd = new CmdMoveCopy(wControl, false); else if (command.equals(COMMAND_ZIP)) cmd = new CmdZip(ureq,wControl); + else if (command.equals(COMMAND_DOWNLOAD_ZIP)) cmd = new CmdDownloadZip(); else if (command.equals(COMMAND_UNZIP)) cmd = new CmdUnzip(ureq,wControl); else if (command.equals(COMMAND_VIEW_VERSION)) cmd = new CmdViewRevisions(ureq,wControl); else if (command.equals(COMMAND_ADD_EPORTFOLIO)) { diff --git a/src/main/java/org/olat/core/commons/modules/bc/components/FolderComponentRenderer.java b/src/main/java/org/olat/core/commons/modules/bc/components/FolderComponentRenderer.java index d87a577451c..b647fb16599 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/components/FolderComponentRenderer.java +++ b/src/main/java/org/olat/core/commons/modules/bc/components/FolderComponentRenderer.java @@ -232,6 +232,12 @@ public class FolderComponentRenderer extends DefaultComponentRenderer { target.append("\" />"); } + target.append("<input type=\"submit\" class='btn btn-default' name=\""); + target.append(FolderRunController.ACTION_PRE).append(FolderCommandFactory.COMMAND_DOWNLOAD_ZIP); + target.append("\" value=\""); + target.append(StringHelper.escapeHtml(translator.translate("download"))); + target.append("\" />"); + if (canDelete) { // delete target.append("<input type=\"submit\" class='btn btn-default' name=\""); diff --git a/src/main/java/org/olat/core/commons/modules/bc/components/ListRenderer.java b/src/main/java/org/olat/core/commons/modules/bc/components/ListRenderer.java index e84b323d3f2..38f629375ec 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/components/ListRenderer.java +++ b/src/main/java/org/olat/core/commons/modules/bc/components/ListRenderer.java @@ -204,8 +204,6 @@ public class ListRenderer { // assume full access unless security callback tells us something different. boolean canWrite = child.getParentContainer().canWrite() == VFSConstants.YES; - boolean canDelete = child.getParentContainer().canDelete() == VFSConstants.YES; - boolean canMail = fc.isCanMail(); boolean isAbstract = (child instanceof AbstractVirtualContainer); Versions versions = null; @@ -234,24 +232,22 @@ public class ListRenderer { String name = child.getName(); String pathAndName = currentContainerPath; - if (pathAndName.length() > 0 && !pathAndName.endsWith("/")) + if (pathAndName.length() > 0 && !pathAndName.endsWith("/")) { pathAndName = pathAndName + "/"; + } pathAndName = pathAndName + name; // tr begin - sb.append("<tr><td>"); - + sb.append("<tr><td>") // add checkbox for actions if user can write, delete or email this directory - if (canWrite || canDelete || canMail) { - sb.append("<input type=\"checkbox\" name=\""); - sb.append(FileSelection.FORM_ID); - sb.append("\" value=\""); - sb.append(StringHelper.escapeHtml(name)); - sb.append("\" /> "); - } - + .append("<input type=\"checkbox\" name=\"") + .append(FileSelection.FORM_ID) + .append("\" value=\"") + .append(StringHelper.escapeHtml(name)) + .append("\" /> ") // browse link pre - sb.append("<a id='o_sel_doc_").append(pos).append("' href=\""); + .append("<a id='o_sel_doc_").append(pos).append("' href=\""); + if (isContainer) { // for directories... normal module URIs ubu.buildURI(sb, null, null, pathAndName, iframePostEnabled ? AJAXFlags.MODE_TOBGIFRAME : AJAXFlags.MODE_NORMAL); sb.append("\""); -- GitLab