From 84fb3480278915e79f1ed98fa0f7ea8173dc66ae Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Tue, 20 Jan 2015 13:20:49 +0100
Subject: [PATCH] OO-1397: zip on the fly scorm and cp content for download

---
 .../ZippedDirectoryMediaResource.java         | 118 ++++++++++++++++++
 .../java/org/olat/ims/cp/CPManagerImpl.java   |   1 -
 .../repository/handlers/QTISurveyHandler.java |   7 ++
 .../repository/handlers/QTITestHandler.java   |   7 ++
 .../olat/repository/handlers/FileHandler.java |   5 -
 .../repository/handlers/ImsCPHandler.java     |  11 ++
 .../repository/handlers/SCORMCPHandler.java   |  11 ++
 .../handlers/WebDocumentHandler.java          |   6 +
 8 files changed, 160 insertions(+), 6 deletions(-)
 create mode 100644 src/main/java/org/olat/fileresource/ZippedDirectoryMediaResource.java

diff --git a/src/main/java/org/olat/fileresource/ZippedDirectoryMediaResource.java b/src/main/java/org/olat/fileresource/ZippedDirectoryMediaResource.java
new file mode 100644
index 00000000000..d0c2d9ed17b
--- /dev/null
+++ b/src/main/java/org/olat/fileresource/ZippedDirectoryMediaResource.java
@@ -0,0 +1,118 @@
+/**
+ * <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.fileresource;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.olat.core.gui.media.MediaResource;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+import org.olat.core.util.FileUtils;
+import org.olat.core.util.StringHelper;
+
+/**
+ * 
+ * Initial date: 20.01.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class ZippedDirectoryMediaResource implements MediaResource {
+	
+	private static final OLog log = Tracing.createLoggerFor(ZippedDirectoryMediaResource.class);
+	
+	private final String filename;
+	private final File unzipDir;
+	
+	public ZippedDirectoryMediaResource(String filename, File unzipDir) {
+		this.filename = filename;
+		this.unzipDir = unzipDir;
+	}
+
+	@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) {
+		String label = StringHelper.transformDisplayNameToFileSystemName(filename) + ".zip";
+		String urlEncodedLabel = StringHelper.urlEncodeUTF8(label);
+		hres.setHeader("Content-Disposition","attachment; filename*=UTF-8''" + urlEncodedLabel);			
+		hres.setHeader("Content-Description", urlEncodedLabel);
+		
+		try(ZipOutputStream zout = new ZipOutputStream(hres.getOutputStream())) {
+			zout.setLevel(9);
+			
+			final Path unzipPath = unzipDir.toPath();
+			Files.walkFileTree(unzipPath, new SimpleFileVisitor<Path>() {
+				@Override
+				public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+					if(!attrs.isDirectory()) {
+						Path relativeFile = unzipPath.relativize(file);
+						String names = relativeFile.toString();
+						zout.putNextEntry(new ZipEntry(names));
+						
+						try(InputStream in=Files.newInputStream(file)) {
+							FileUtils.copy(in, zout);
+						} catch (Exception e) {
+							log.error("", e);
+						}
+						
+						zout.closeEntry();
+					}
+					return FileVisitResult.CONTINUE;
+				}
+			});
+		} catch (Exception e) {
+			log.error("", e);
+		}
+	}
+
+	@Override
+	public void release() {
+		//
+	}
+}
diff --git a/src/main/java/org/olat/ims/cp/CPManagerImpl.java b/src/main/java/org/olat/ims/cp/CPManagerImpl.java
index d57bd5047f8..0d1695f690a 100644
--- a/src/main/java/org/olat/ims/cp/CPManagerImpl.java
+++ b/src/main/java/org/olat/ims/cp/CPManagerImpl.java
@@ -176,7 +176,6 @@ public class CPManagerImpl extends CPManager {
 			File cpRoot = FileResourceManager.getInstance().unzipFileResource(ores);
 			logDebug("createNewCP: cpRoot=" + cpRoot);
 			logDebug("createNewCP: cpRoot.getAbsolutePath()=" + cpRoot.getAbsolutePath());
-			System.out.println("createNewCP: cpRoot.getAbsolutePath()=" + cpRoot.getAbsolutePath());
 			LocalFolderImpl vfsWrapper = new LocalFolderImpl(cpRoot);
 			ContentPackage cp = load(vfsWrapper, ores);
 
diff --git a/src/main/java/org/olat/ims/qti/repository/handlers/QTISurveyHandler.java b/src/main/java/org/olat/ims/qti/repository/handlers/QTISurveyHandler.java
index fbffb2db924..3db84d3a09c 100644
--- a/src/main/java/org/olat/ims/qti/repository/handlers/QTISurveyHandler.java
+++ b/src/main/java/org/olat/ims/qti/repository/handlers/QTISurveyHandler.java
@@ -36,9 +36,11 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.layout.MainLayoutController;
 import org.olat.core.gui.control.generic.wizard.StepsMainRunController;
+import org.olat.core.gui.media.MediaResource;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.AssertException;
+import org.olat.fileresource.FileResourceManager;
 import org.olat.fileresource.types.ResourceEvaluation;
 import org.olat.ims.qti.QTIRuntimeController;
 import org.olat.ims.qti.editor.QTIEditorMainController;
@@ -102,6 +104,11 @@ public class QTISurveyHandler extends QTIHandler {
 		return super.importResource(initialAuthor, displayname, description, new SurveyFileResource(), file, filename);
 	}
 
+	@Override
+	public MediaResource getAsMediaResource(OLATResourceable res, boolean backwardsCompatible) {
+		return FileResourceManager.getInstance().getAsDownloadeableMediaResource(res);
+	}
+
 	@Override
 	public String getSupportedType() {
 		return SurveyFileResource.TYPE_NAME;
diff --git a/src/main/java/org/olat/ims/qti/repository/handlers/QTITestHandler.java b/src/main/java/org/olat/ims/qti/repository/handlers/QTITestHandler.java
index 358f795232f..247818a4117 100644
--- a/src/main/java/org/olat/ims/qti/repository/handlers/QTITestHandler.java
+++ b/src/main/java/org/olat/ims/qti/repository/handlers/QTITestHandler.java
@@ -36,9 +36,11 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.layout.MainLayoutController;
 import org.olat.core.gui.control.generic.wizard.StepsMainRunController;
+import org.olat.core.gui.media.MediaResource;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.AssertException;
+import org.olat.fileresource.FileResourceManager;
 import org.olat.fileresource.types.ResourceEvaluation;
 import org.olat.ims.qti.QTIRuntimeController;
 import org.olat.ims.qti.editor.QTIEditorMainController;
@@ -102,6 +104,11 @@ public class QTITestHandler extends QTIHandler {
 		return super.importResource(initialAuthor, displayname, description, new TestFileResource(), file, filename);
 	}
 
+	@Override
+	public MediaResource getAsMediaResource(OLATResourceable res, boolean backwardsCompatible) {
+		return FileResourceManager.getInstance().getAsDownloadeableMediaResource(res);
+	}
+
 	@Override
 	public String getSupportedType() {
 		return TestFileResource.TYPE_NAME;
diff --git a/src/main/java/org/olat/repository/handlers/FileHandler.java b/src/main/java/org/olat/repository/handlers/FileHandler.java
index e36108471a7..0b22fe8f133 100644
--- a/src/main/java/org/olat/repository/handlers/FileHandler.java
+++ b/src/main/java/org/olat/repository/handlers/FileHandler.java
@@ -55,11 +55,6 @@ public abstract class FileHandler implements RepositoryHandler {
 		//
 	}
 
-	@Override
-	public MediaResource getAsMediaResource(OLATResourceable res, boolean backwardsCompatible) {
-		return FileResourceManager.getInstance().getAsDownloadeableMediaResource(res);
-	}
-	
 	@Override
 	public VFSContainer getMediaContainer(RepositoryEntry repoEntry) {
 		return FileResourceManager.getInstance()
diff --git a/src/main/java/org/olat/repository/handlers/ImsCPHandler.java b/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
index 16fce20e36c..da69365f02a 100644
--- a/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
+++ b/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
@@ -41,6 +41,7 @@ import org.olat.core.gui.control.generic.iframe.DeliveryOptions;
 import org.olat.core.gui.control.generic.layout.MainLayout3ColumnsController;
 import org.olat.core.gui.control.generic.layout.MainLayoutController;
 import org.olat.core.gui.control.generic.wizard.StepsMainRunController;
+import org.olat.core.gui.media.MediaResource;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
@@ -54,6 +55,7 @@ import org.olat.core.util.vfs.QuotaManager;
 import org.olat.core.util.vfs.callbacks.FullAccessWithQuotaCallback;
 import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
 import org.olat.fileresource.FileResourceManager;
+import org.olat.fileresource.ZippedDirectoryMediaResource;
 import org.olat.fileresource.types.FileResource;
 import org.olat.fileresource.types.ImsCPFileResource;
 import org.olat.fileresource.types.ResourceEvaluation;
@@ -65,6 +67,7 @@ import org.olat.ims.cp.ui.CPRuntimeController;
 import org.olat.modules.cp.CPDisplayController;
 import org.olat.modules.cp.CPOfflineReadableManager;
 import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
 import org.olat.repository.RepositoryService;
 import org.olat.repository.model.RepositoryEntrySecurity;
 import org.olat.repository.ui.RepositoryEntryRuntimeController.RuntimeControllerCreator;
@@ -155,6 +158,14 @@ public class ImsCPHandler extends FileHandler {
 		return target;
 	}
 
+	@Override
+	public MediaResource getAsMediaResource(OLATResourceable res, boolean backwardsCompatible) {
+		File unzippedDir = FileResourceManager.getInstance().unzipFileResource(res);
+		String displayName = CoreSpringFactory.getImpl(RepositoryManager.class)
+				.lookupDisplayNameByOLATResourceableId(res.getResourceableId());
+		return new ZippedDirectoryMediaResource(displayName, unzippedDir);
+	}
+
 	@Override
 	public String getSupportedType() {
 		return ImsCPFileResource.TYPE_NAME;
diff --git a/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java b/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java
index 7cc65dd5c37..ac6ac06256a 100644
--- a/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java
+++ b/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java
@@ -36,6 +36,7 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.layout.MainLayoutController;
 import org.olat.core.gui.control.generic.wizard.StepsMainRunController;
+import org.olat.core.gui.media.MediaResource;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.AssertException;
@@ -43,6 +44,7 @@ import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.util.FileUtils;
 import org.olat.core.util.coordinate.LockResult;
 import org.olat.fileresource.FileResourceManager;
+import org.olat.fileresource.ZippedDirectoryMediaResource;
 import org.olat.fileresource.types.FileResource;
 import org.olat.fileresource.types.ResourceEvaluation;
 import org.olat.fileresource.types.ScormCPFileResource;
@@ -50,6 +52,7 @@ import org.olat.modules.scorm.ScormMainManager;
 import org.olat.modules.scorm.ScormPackageConfig;
 import org.olat.modules.scorm.ScormRuntimeController;
 import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
 import org.olat.repository.RepositoryService;
 import org.olat.repository.model.RepositoryEntrySecurity;
 import org.olat.repository.ui.RepositoryEntryRuntimeController.RuntimeControllerCreator;
@@ -127,6 +130,14 @@ public class SCORMCPHandler extends FileHandler {
 		}
 		return target;
 	}
+	
+	@Override
+	public MediaResource getAsMediaResource(OLATResourceable res, boolean backwardsCompatible) {
+		File unzippedDir = FileResourceManager.getInstance().unzipFileResource(res);
+		String displayName = CoreSpringFactory.getImpl(RepositoryManager.class)
+				.lookupDisplayNameByOLATResourceableId(res.getResourceableId());
+		return new ZippedDirectoryMediaResource(displayName, unzippedDir);
+	}
 
 	@Override
 	public String getSupportedType() {
diff --git a/src/main/java/org/olat/repository/handlers/WebDocumentHandler.java b/src/main/java/org/olat/repository/handlers/WebDocumentHandler.java
index 6b14372bc22..0ad4cdc410c 100644
--- a/src/main/java/org/olat/repository/handlers/WebDocumentHandler.java
+++ b/src/main/java/org/olat/repository/handlers/WebDocumentHandler.java
@@ -39,6 +39,7 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.layout.MainLayoutController;
 import org.olat.core.gui.control.generic.wizard.StepsMainRunController;
+import org.olat.core.gui.media.MediaResource;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.AssertException;
@@ -186,6 +187,11 @@ public class WebDocumentHandler extends FileHandler {
 		return target;
 	}
 
+	@Override
+	public MediaResource getAsMediaResource(OLATResourceable res, boolean backwardsCompatible) {
+		return FileResourceManager.getInstance().getAsDownloadeableMediaResource(res);
+	}
+
 	@Override
 	public String getSupportedType() {
 		return supportedType;
-- 
GitLab