Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java =================================================================== diff -u -r96033f32ff880d045b4c087f52628d233dc98095 -rb66f7e21a3e56f7a351182a497045bfe780ae969 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision 96033f32ff880d045b4c087f52628d233dc98095) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision b66f7e21a3e56f7a351182a497045bfe780ae969) @@ -545,7 +545,7 @@ String secureDir = Configuration.get(ConfigurationKeys.LAMS_EAR_DIR) + File.separator + FileUtil.LAMS_WWW_DIR + File.separator + FileUtil.LAMS_WWW_SECURE_DIR; - String contentFolder = ExportToolContentService.getContentDirPath(contentFolderID, true); + String contentFolder = FileUtil.getContentDirPath(contentFolderID, true); contentFolder = FileUtil.getFullPath(secureDir, contentFolder); if (!FileUtil.isEmptyDirectory(contentFolder, true)) { @@ -729,7 +729,7 @@ // into new format of paths like secure/40/28/81/39/15/76/ String oldResourcePath = FileUtil.LAMS_WWW_SECURE_DIR + '/' + ldDto.getContentFolderID() + '/'; String newResourcePath = FileUtil.LAMS_WWW_SECURE_DIR + '/' - + ExportToolContentService.getContentDirPath(ldDto.getContentFolderID(), false); + + FileUtil.getContentDirPath(ldDto.getContentFolderID(), false); if (rewriteResourcePaths && ldDto.getDescription() != null) { ldDto.setDescription(ldDto.getDescription().replaceAll(oldResourcePath, newResourcePath)); } @@ -856,7 +856,7 @@ + ExportToolContentService.EXPORT_CONTENT_ZIP_SUFFIX; String secureDir = Configuration.get(ConfigurationKeys.LAMS_EAR_DIR) + File.separator + FileUtil.LAMS_WWW_DIR + File.separator + FileUtil.LAMS_WWW_SECURE_DIR + File.separator - + ExportToolContentService.getContentDirPath(contentFolderID, true); + + FileUtil.getContentDirPath(contentFolderID, true); File contentZipFile = new File(FileUtil.getFullPath(sourceDir, contentZipFileName)); // unzip file to target secure dir if exists @@ -2031,19 +2031,6 @@ act.setEndYcoord(actDto.getEndYCoord()); } - /** - * Convert content folder ID to real path inside secure dir or on server - */ - private static String getContentDirPath(String contentFolderID, boolean isFileSystemPath) { - String contentFolderIDClean = contentFolderID.replaceAll("-", ""); - String contentDir = ""; - for (int charIndex = 0; charIndex < 6; charIndex++) { - contentDir += contentFolderIDClean.substring(charIndex * 2, charIndex * 2 + 2) - + (isFileSystemPath ? File.separator : "/"); - } - return contentDir; - } - // ****************************************************************** // Spring injection properties set/get // ****************************************************************** Index: lams_common/src/java/org/lamsfoundation/lams/util/FileUtil.java =================================================================== diff -u -rf3ef538574537ba41f51bef0335ee6df8495c987 -rb66f7e21a3e56f7a351182a497045bfe780ae969 --- lams_common/src/java/org/lamsfoundation/lams/util/FileUtil.java (.../FileUtil.java) (revision f3ef538574537ba41f51bef0335ee6df8495c987) +++ lams_common/src/java/org/lamsfoundation/lams/util/FileUtil.java (.../FileUtil.java) (revision b66f7e21a3e56f7a351182a497045bfe780ae969) @@ -24,21 +24,23 @@ package org.lamsfoundation.lams.util; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.Reader; +import java.io.StringReader; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; +import java.nio.file.Files; +import java.nio.file.Paths; import java.text.SimpleDateFormat; import java.time.format.DateTimeFormatter; import java.util.Collection; import java.util.Date; import java.util.Map; import java.util.Properties; +import java.util.regex.Pattern; import javax.mail.internet.MimeUtility; import javax.servlet.http.HttpServletRequest; @@ -91,6 +93,10 @@ public static final String LAMS_RUNTIME_CONTENT_DIR = "runtime"; private static final long numMilliSecondsInADay = 24 * 60 * 60 * 1000; + // looks for URL with non-chopped content folder ID + private static final Pattern LEGACY_CONTENT_FOLDER_PATH = Pattern + .compile("/+lams/+www/+secure/+([0-9a-f\\-]{3,}/+).*?[\"']", Pattern.CASE_INSENSITIVE); + public static final String ALLOWED_EXTENSIONS_FLASH = ".swf,.fla"; public static final String ALLOWED_EXTENSIONS_IMAGE = ".jpg,.gif,.jpeg,.png,.bmp"; public static final String ALLOWED_EXTENSIONS_MEDIA = ".3gp,.avi,.flv,.m4v,.mkv,.mov,.mp3,.mp4,.mpe,.mpeg,.mpg,.mpv,.mts,.m2ts,ogg,.wma,.wmv"; @@ -654,13 +660,35 @@ IdentifierGenerator uuidGen = new UUIDGenerator(); ((Configurable) uuidGen).configure(StringType.INSTANCE, new Properties(), null); -// Serializable generate(SharedSessionContractImplementor session, Object object) - // lowercase to resolve OS issues return ((String) uuidGen.generate(null, null)).toLowerCase(); } /** + * Convert content folder ID to real path inside secure dir or on server + */ + public static String getContentDirPath(String contentFolderID, boolean isFileSystemPath) { + String contentFolderIDClean = contentFolderID.replaceAll("-", ""); + String contentDir = ""; + for (int charIndex = 0; charIndex < 6; charIndex++) { + contentDir += contentFolderIDClean.substring(charIndex * 2, charIndex * 2 + 2) + + (isFileSystemPath ? File.separator : "/"); + } + return contentDir; + } + + public static String structureContentDirPath(String text) { + // example path: /lams//www/secure/ff808181292370660129c52061536966/Image//matthew.jpg + // This method looks for non-chopped, legacy content folder IDs and replaces them with multi-part version + // Also it cleans up duplicate slashes in URL + return StringUtils.isBlank(text) ? text : LEGACY_CONTENT_FOLDER_PATH.matcher(text).replaceAll(matchResult -> { + return matchResult.group() + .replace(matchResult.group(1), FileUtil.getContentDirPath(matchResult.group(1), false)) + .replaceAll("/{2,}", "/"); + }); + } + + /** * Return content folder (unique to each learner and lesson) which is used for storing user generated content. It's * been used by CKEditor. * @@ -707,7 +735,7 @@ */ public static Object getObjectFromXML(XStream xStream, String fullFilePath) throws IOException { - Reader file = null; + Reader reader = null; XStream conversionXml = xStream != null ? xStream : new XStream(new StaxDriver()); // allow parsing all classes conversionXml.addPermission(AnyTypePermission.ANY); @@ -729,13 +757,16 @@ } numTries++; - file = new InputStreamReader(new FileInputStream(fullFilePath), FileUtil.ENCODING_UTF_8); - return conversionXml.fromXML(file); + String xmlContent = Files.readString(Paths.get(fullFilePath)); + // look for legacy, non-chopped content folder IDs and replace them with multi-part version + xmlContent = FileUtil.structureContentDirPath(xmlContent); + reader = new StringReader(xmlContent); + return conversionXml.fromXML(reader); } catch (ConversionException ce) { FileUtil.log.debug("Failed import", ce); finalException = ce; - file.close(); + reader.close(); if (ce.getMessage() == null) { // can't retry, so get out of here! @@ -776,8 +807,8 @@ } } } finally { - if (file != null) { - file.close(); + if (reader != null) { + reader.close(); } } }