diff --git a/src/main/java/de/bps/onyx/plugin/OnyxModule.java b/src/main/java/de/bps/onyx/plugin/OnyxModule.java index 2d1a182fbafad9fc05c968b3a39d662b251f6897..2a1fb3eb116582724dcdf357249495bbcecf5b3f 100644 --- a/src/main/java/de/bps/onyx/plugin/OnyxModule.java +++ b/src/main/java/de/bps/onyx/plugin/OnyxModule.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.FileVisitResult; import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; @@ -229,6 +230,8 @@ public class OnyxModule extends AbstractOLATModule implements ConfigOnOff { } else { eval.setValid(false); } + } catch(NoSuchFileException nsfe) { + eval.setValid(false); } catch (IOException e) { log.error("", e); eval.setValid(false); diff --git a/src/main/java/org/olat/fileresource/types/FileResource.java b/src/main/java/org/olat/fileresource/types/FileResource.java index 6b59723891211d116a3767bbff677a828b6dee1c..53e095e482817335887f78201877822d074a9e4a 100644 --- a/src/main/java/org/olat/fileresource/types/FileResource.java +++ b/src/main/java/org/olat/fileresource/types/FileResource.java @@ -112,13 +112,24 @@ public class FileResource implements OLATResourceable { } else if(filename != null && filename.toLowerCase().endsWith(".zip")) { //perhaps find root folder and return it fPath = FileSystems.newFileSystem(file.toPath(), null).getPath("/"); + RootSearcher rootSearcher = searchRootDirectory(fPath); + if(rootSearcher.foundRoot()) { + Path rootPath = rootSearcher.getRoot(); + fPath = fPath.resolve(rootPath); + } } else { fPath = file.toPath(); } - return fPath; } + protected static RootSearcher searchRootDirectory(Path fPath) + throws IOException { + RootSearcher rootSearcher = new RootSearcher(); + Files.walkFileTree(fPath, rootSearcher); + return rootSearcher; + } + public static boolean copyResource(File file, String filename, File targetDirectory) { return copyResource(file, filename, targetDirectory, new YesMatcher()); } @@ -131,13 +142,45 @@ public class FileResource implements OLATResourceable { } Path destDir = targetDirectory.toPath(); - Files.walkFileTree(path, new CopyVisitor(destDir, filter)); + Files.walkFileTree(path, new CopyVisitor(path, destDir, filter)); return true; } catch (IOException e) { log.error("", e); return false; } } + + public static class RootSearcher extends SimpleFileVisitor<Path> { + + private Path root; + private boolean rootFound = false; + + public Path getRoot() { + return root; + } + + public boolean foundRoot() { + return root != null && rootFound; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + Path tokenZero = file.getName(0); + if("__MACOSX".equals(tokenZero.toString()) || Files.isHidden(file)) { + //ignore + } else if(root == null) { + if(Files.isRegularFile(file) && file.getNameCount() > 1) { + root = tokenZero; + rootFound = true; + } + } else if(!root.equals(tokenZero)) { + rootFound = false; + return FileVisitResult.TERMINATE; + } + return FileVisitResult.CONTINUE; + } + } public static class YesMatcher implements PathMatcher { @Override @@ -147,11 +190,13 @@ public class FileResource implements OLATResourceable { } public static class CopyVisitor extends SimpleFileVisitor<Path> { - + + private final Path source; private final Path destDir; private final PathMatcher filter; - public CopyVisitor(Path destDir, PathMatcher filter) { + public CopyVisitor(Path source, Path destDir, PathMatcher filter) { + this.source = source; this.destDir = destDir; this.filter = filter; } @@ -159,7 +204,8 @@ public class FileResource implements OLATResourceable { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - final Path destFile = Paths.get(destDir.toString(), file.toString()); + Path relativeFile = source.relativize(file); + final Path destFile = Paths.get(destDir.toString(), relativeFile.toString()); if(filter.matches(file)) { Files.copy(file, destFile, StandardCopyOption.REPLACE_EXISTING); } @@ -169,7 +215,8 @@ public class FileResource implements OLATResourceable { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - final Path dirToCreate = Paths.get(destDir.toString(), dir.toString()); + Path relativeDir = source.relativize(dir); + final Path dirToCreate = Paths.get(destDir.toString(), relativeDir.toString()); if(Files.notExists(dirToCreate)){ Files.createDirectory(dirToCreate); } diff --git a/src/main/java/org/olat/fileresource/types/ImsCPFileResource.java b/src/main/java/org/olat/fileresource/types/ImsCPFileResource.java index 531616c9a55a3dffd044f141ae2f2b154d52dbfd..80a2c3749f790b4f69ab4d161be651647f06c1a7 100644 --- a/src/main/java/org/olat/fileresource/types/ImsCPFileResource.java +++ b/src/main/java/org/olat/fileresource/types/ImsCPFileResource.java @@ -62,30 +62,14 @@ public class ImsCPFileResource extends FileResource { public ImsCPFileResource() { super(TYPE_NAME); } - - /** - * Check for title and at least one resource. - * @param unzippedDir - * @return True if is of type. - */ - public static boolean validate(File unzippedDir) { - File fManifest = new File(unzippedDir, IMS_MANIFEST); - Document doc = IMSLoader.loadIMSDocument(fManifest); - //do not throw exception already here, as it might be only a generic zip file - if (doc == null) { - return false; - } else { - return validateImsManifest(doc); - } - } - + public static ResourceEvaluation evaluate(File file, String filename) { ResourceEvaluation eval = new ResourceEvaluation(); try { ImsManifestFileFilter visitor = new ImsManifestFileFilter(); Path fPath = PathUtils.visit(file, filename, visitor); if(visitor.isValid()) { - Path manifestPath = fPath.resolve(IMS_MANIFEST); + Path manifestPath = fPath.resolve(visitor.getManifestPath()); Document doc = IMSLoader.loadIMSDocument(manifestPath); if(validateImsManifest(doc)) { eval.setValid(true); @@ -170,6 +154,7 @@ public class ImsCPFileResource extends FileResource { private static class ImsManifestFileFilter extends SimpleFileVisitor<Path> { private boolean manifestFile; + private Path manifestPath; @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) @@ -178,6 +163,7 @@ public class ImsCPFileResource extends FileResource { String filename = file.getFileName().toString(); if(IMS_MANIFEST.equals(filename)) { manifestFile = true; + manifestPath = file; } return manifestFile ? FileVisitResult.TERMINATE : FileVisitResult.CONTINUE; } @@ -185,5 +171,9 @@ public class ImsCPFileResource extends FileResource { public boolean isValid() { return manifestFile; } + + public Path getManifestPath() { + return manifestPath; + } } } \ No newline at end of file diff --git a/src/main/java/org/olat/fileresource/types/ScormCPFileResource.java b/src/main/java/org/olat/fileresource/types/ScormCPFileResource.java index 08bff1f5260c6096e0ea1049432597ec83ee5d37..bb7ee23ccaac1e568d3f399465c2729e119b191f 100644 --- a/src/main/java/org/olat/fileresource/types/ScormCPFileResource.java +++ b/src/main/java/org/olat/fileresource/types/ScormCPFileResource.java @@ -28,6 +28,7 @@ package org.olat.fileresource.types; import java.io.File; import java.io.IOException; 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; @@ -67,24 +68,23 @@ public class ScormCPFileResource extends FileResource { super(TYPE_NAME); } - /** - * Check for title and at least one resource. - * @param unzippedDir - * @return True if is of type. - */ - public static boolean validate(File unzippedDir) { - File fManifest = new File(unzippedDir, "imsmanifest.xml"); - Document doc = IMSLoader.loadIMSDocument(fManifest); - return validateImsManifest(doc); - } - public static ResourceEvaluation evaluate(File file, String filename) { ResourceEvaluation eval = new ResourceEvaluation(); try { ImsManifestFileFilter visitor = new ImsManifestFileFilter(); Path fPath = PathUtils.visit(file, filename, visitor); if(visitor.isValid()) { - Path manifestPath = fPath.resolve(IMS_MANIFEST); + Path realManifestPath = visitor.getManifestPath(); + Path manifestPath = fPath.resolve(realManifestPath); + + RootSearcher rootSearcher = new RootSearcher(); + Files.walkFileTree(fPath, rootSearcher); + if(rootSearcher.foundRoot()) { + manifestPath = rootSearcher.getRoot().resolve(IMS_MANIFEST); + } else { + manifestPath = fPath.resolve(IMS_MANIFEST); + } + Document doc = IMSLoader.loadIMSDocument(manifestPath); if(validateImsManifest(doc)) { eval.setValid(true); @@ -214,6 +214,7 @@ public class ScormCPFileResource extends FileResource { private static class ImsManifestFileFilter extends SimpleFileVisitor<Path> { private boolean manifestFile; + private Path manifestPath; @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) @@ -222,6 +223,7 @@ public class ScormCPFileResource extends FileResource { String filename = file.getFileName().toString(); if(IMS_MANIFEST.equals(filename)) { manifestFile = true; + manifestPath = file; } return manifestFile ? FileVisitResult.TERMINATE : FileVisitResult.CONTINUE; } @@ -229,5 +231,9 @@ public class ScormCPFileResource extends FileResource { public boolean isValid() { return manifestFile; } + + public Path getManifestPath() { + return manifestPath; + } } } diff --git a/src/test/java/org/olat/fileresource/FileResourceTest.java b/src/test/java/org/olat/fileresource/FileResourceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..977724ea019581b4a52f9b8e226ca50cd805d15f --- /dev/null +++ b/src/test/java/org/olat/fileresource/FileResourceTest.java @@ -0,0 +1,76 @@ +/** + * <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.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Path; + +import junit.framework.Assert; + +import org.junit.Test; +import org.olat.fileresource.types.FileResource; +import org.olat.fileresource.types.ResourceEvaluation; +import org.olat.fileresource.types.ScormCPFileResource; + +/** + * + * Initial date: 25.07.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class FileResourceTest { + + @Test + public void scormPackage() throws URISyntaxException { + URL fileUrl = FileResourceTest.class.getResource("very_simple_scorm.zip"); + File file = new File(fileUrl.toURI()); + ResourceEvaluation eval = ScormCPFileResource.evaluate(file, file.getName()); + Assert.assertTrue(eval.isValid()); + } + + @Test + public void scormPackage_withinDirectory() throws URISyntaxException { + URL fileUrl = FileResourceTest.class.getResource("very_simple_scorm_in_directory.zip"); + File file = new File(fileUrl.toURI()); + ResourceEvaluation eval = ScormCPFileResource.evaluate(file, file.getName()); + Assert.assertTrue(eval.isValid()); + } + + @Test + public void scormPackage_invalid() throws URISyntaxException { + URL fileUrl = FileResourceTest.class.getResource("invalid_scorm.zip"); + File file = new File(fileUrl.toURI()); + ResourceEvaluation eval = ScormCPFileResource.evaluate(file, file.getName()); + Assert.assertFalse(eval.isValid()); + } + + @Test + public void qtiPackage() throws URISyntaxException, IOException { + URL fileUrl = FileResourceTest.class.getResource("qti.zip"); + File file = new File(fileUrl.toURI()); + Path path = FileResource.getResource(file, file.getName()); + //must be root + Assert.assertEquals(0, path.getNameCount()); + } + +} diff --git a/src/test/java/org/olat/fileresource/invalid_scorm.zip b/src/test/java/org/olat/fileresource/invalid_scorm.zip new file mode 100644 index 0000000000000000000000000000000000000000..944a1ef73d590fa77149d56c204a6f5fbe9c0987 Binary files /dev/null and b/src/test/java/org/olat/fileresource/invalid_scorm.zip differ diff --git a/src/test/java/org/olat/fileresource/qti.zip b/src/test/java/org/olat/fileresource/qti.zip new file mode 100644 index 0000000000000000000000000000000000000000..3709bbcc2ce21c7ce0ab1c9d9dc341af5bda0055 Binary files /dev/null and b/src/test/java/org/olat/fileresource/qti.zip differ diff --git a/src/test/java/org/olat/fileresource/very_simple_scorm.zip b/src/test/java/org/olat/fileresource/very_simple_scorm.zip new file mode 100644 index 0000000000000000000000000000000000000000..5703afdeed8f4f6cb69131e886ddffdaafc87983 Binary files /dev/null and b/src/test/java/org/olat/fileresource/very_simple_scorm.zip differ diff --git a/src/test/java/org/olat/fileresource/very_simple_scorm_in_directory.zip b/src/test/java/org/olat/fileresource/very_simple_scorm_in_directory.zip new file mode 100644 index 0000000000000000000000000000000000000000..c1757253ff1d8d4839231ab07f1ede80259c6c45 Binary files /dev/null and b/src/test/java/org/olat/fileresource/very_simple_scorm_in_directory.zip differ diff --git a/src/test/java/org/olat/modules/coach/CoachingDAOTest.java b/src/test/java/org/olat/modules/coach/CoachingDAOTest.java index 11c747222d3e0616a441fce0a95fd45bb366df1e..ae8b7376a095b012ba6b2f3bb4fbdba0ca6dfa5e 100644 --- a/src/test/java/org/olat/modules/coach/CoachingDAOTest.java +++ b/src/test/java/org/olat/modules/coach/CoachingDAOTest.java @@ -1,3 +1,22 @@ +/** + * <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.modules.coach; import java.io.File; @@ -21,6 +40,12 @@ import org.olat.test.JunitTestHelper; import org.olat.test.OlatTestCase; import org.springframework.beans.factory.annotation.Autowired; +/** + * + * Initial date: 24.07.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ public class CoachingDAOTest extends OlatTestCase { @Autowired diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java index 8ea0619c5ec5fff2ada072f53390434196b7d4c5..4de668b9a2a1b49c6f8647e38d8792becfc4868b 100644 --- a/src/test/java/org/olat/test/AllTestsJunit4.java +++ b/src/test/java/org/olat/test/AllTestsJunit4.java @@ -93,6 +93,7 @@ import org.junit.runners.Suite; org.olat.group.test.BusinessGroupRelationDAOTest.class,//ok org.olat.group.test.BusinessGroupConcurrentTest.class,//ok org.olat.group.test.ContactDAOTest.class,//ok + org.olat.fileresource.FileResourceTest.class,//ok org.olat.resource.lock.pessimistic.PLockTest.class,//ok org.olat.resource.references.ReferenceManagerTest.class,//ok org.olat.resource.OLATResourceManagerTest.class,//ok @@ -127,6 +128,7 @@ import org.junit.runners.Suite; org.olat.modules.wiki.WikiUnitTest.class,//ok org.olat.modules.wiki.versioning.diff.CookbookDiffTest.class,//ok org.olat.modules.wiki.gui.components.wikiToHtml.FilterUtilTest.class, + org.olat.modules.coach.CoachingDAOTest.class,//ok org.olat.modules.coach.CoachingServiceTest.class,//ok org.olat.properties.PropertyTest.class,//ok org.olat.search.service.document.file.FileDocumentFactoryTest.class,