Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -rc6d1e011ff92ac2a8b0581efa0982100101c70b7 -r0dbc1d60bc9b43c26c431c9a2e15981ca0863d46 Binary files differ Index: lams_central/src/java/org/lamsfoundation/lams/web/LAMSUploadServlet.java =================================================================== diff -u -rf78211d8d91db7e763371407f0ea29973542b5c2 -r0dbc1d60bc9b43c26c431c9a2e15981ca0863d46 --- lams_central/src/java/org/lamsfoundation/lams/web/LAMSUploadServlet.java (.../LAMSUploadServlet.java) (revision f78211d8d91db7e763371407f0ea29973542b5c2) +++ lams_central/src/java/org/lamsfoundation/lams/web/LAMSUploadServlet.java (.../LAMSUploadServlet.java) (revision 0dbc1d60bc9b43c26c431c9a2e15981ca0863d46) @@ -23,10 +23,7 @@ import org.apache.commons.fileupload.DiskFileUpload; import org.apache.commons.fileupload.FileItem; import org.apache.log4j.Logger; -import org.lamsfoundation.lams.authoring.web.AuthoringConstants; -import org.lamsfoundation.lams.util.Configuration; -import org.lamsfoundation.lams.util.ConfigurationKeys; -import org.lamsfoundation.lams.util.FileUtil; +import org.lamsfoundation.lams.util.UploadFileUtil; /** * Servlet to upload files.
@@ -43,9 +40,6 @@ * @author Mitchell Seaton * * @web:servlet name="SimpleUploader" load-on-startup = "1" - * @web.servlet-init-param name = "baseDir" value = "secure" - * @web.servlet-init-param name = "debug" value = "true" - * @web.servlet-init-param name = "enabled" value = "true" * @web.servlet-init-param name = "AllowedExtensionsFile" value = "" * @web.servlet-init-param name = "DeniedExtensionsFile" value = * "php|php3|php5|phtml|asp|aspx|ascx|jsp|cfm|cfc|pl|bat|exe|dll|reg|cg" @@ -58,18 +52,11 @@ */ public class LAMSUploadServlet extends HttpServlet { - private static final Logger log = Logger.getLogger(LAMSUploadServlet.class); - private static String baseDir; - private static boolean debug = false; - private static boolean enabled = false; private static Hashtable> allowedExtensions; private static Hashtable> deniedExtensions; - private String realBaseDir; - private String lamsContextPath; - /** * Initialize the servlet.
* Retrieve from the servlet configuration the "baseDir" which is the root of the file repository:
@@ -79,28 +66,10 @@ */ @Override public void init() throws ServletException { - - LAMSUploadServlet.debug = (new Boolean(getInitParameter("debug"))).booleanValue() - && LAMSUploadServlet.log.isDebugEnabled(); - - if (LAMSUploadServlet.debug) { + if (LAMSUploadServlet.log.isDebugEnabled()) { LAMSUploadServlet.log.debug("Initialization started"); } - LAMSUploadServlet.baseDir = getInitParameter("baseDir"); - LAMSUploadServlet.enabled = (new Boolean(getInitParameter("enabled"))).booleanValue(); - - if (LAMSUploadServlet.baseDir == null) { - LAMSUploadServlet.baseDir = "secure"; - } - - getConfigKeyValues(); - - File baseFile = new File(realBaseDir); - if (!baseFile.exists()) { - baseFile.mkdir(); - } - LAMSUploadServlet.allowedExtensions = new Hashtable>(3); LAMSUploadServlet.deniedExtensions = new Hashtable>(3); @@ -113,7 +82,7 @@ LAMSUploadServlet.allowedExtensions.put("Flash", stringToArrayList(getInitParameter("AllowedExtensionsFlash"))); LAMSUploadServlet.deniedExtensions.put("Flash", stringToArrayList(getInitParameter("DeniedExtensionsFlash"))); - if (LAMSUploadServlet.debug) { + if (LAMSUploadServlet.log.isDebugEnabled()) { LAMSUploadServlet.log.debug("Initialization completed"); } } @@ -128,9 +97,10 @@ * javascript command in it. * */ + @SuppressWarnings("unchecked") @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - if (LAMSUploadServlet.debug) { + if (LAMSUploadServlet.log.isDebugEnabled()) { LAMSUploadServlet.log.debug("Upload started"); } @@ -144,83 +114,52 @@ returnMessage = "Security error. You probably don't have enough permissions to upload. Please check your server."; } else { // get realBaseDir and lamsContextPath at request time from config values in memory - getConfigKeyValues(); String typeStr = request.getParameter("Type"); - // create content directory if non-existant - String currentDirPath = realBaseDir + currentFolderStr; - String validCurrentDirPath = currentDirPath.replace('/', File.separatorChar); - String currentWebPath = lamsContextPath + AuthoringConstants.LAMS_WWW_FOLDER + FileUtil.LAMS_WWW_SECURE_DIR - + currentFolderStr + typeStr; + DiskFileUpload upload = new DiskFileUpload(); + try { + List items = upload.parseRequest(request); + Map fields = new HashMap(); - File currentContentDir = new File(validCurrentDirPath); - if (!currentContentDir.exists()) { - currentContentDir.mkdir(); - } + Iterator iter = items.iterator(); + while (iter.hasNext()) { + FileItem item = iter.next(); + if (item.isFormField()) { + fields.put(item.getFieldName(), item.getString()); + } else { + fields.put(item.getFieldName(), item); + } + } + FileItem uplFile = (FileItem) fields.get("NewFile"); + if (uplFile == null) { + // form field name used by CKEditor 3.x + uplFile = (FileItem) fields.get("upload"); + } - // create content type directory if non-existant - validCurrentDirPath += typeStr; + String fileNameLong = uplFile.getName(); + fileNameLong = fileNameLong.replace('\\', '/'); + String[] pathParts = fileNameLong.split("/"); + String fileName = pathParts[pathParts.length - 1]; + String ext = UploadFileUtil.getFileExtension(fileName); - File currentDir = new File(validCurrentDirPath); - if (!currentDir.exists()) { - currentDir.mkdir(); - } + if (extIsAllowed(typeStr, ext)) { + File uploadDir = UploadFileUtil.getUploadDir(currentFolderStr, typeStr); + fileName = UploadFileUtil.getUploadFileName(uploadDir, fileName); + File destinationFile = new File(uploadDir, fileName); - if (LAMSUploadServlet.debug) { - LAMSUploadServlet.log.debug(currentDirPath); - } + String currentWebPath = UploadFileUtil.getUploadWebPath(currentFolderStr, typeStr); + fileUrl = currentWebPath + '/' + fileName; - if (LAMSUploadServlet.enabled) { - DiskFileUpload upload = new DiskFileUpload(); - try { - List items = upload.parseRequest(request); - - Map fields = new HashMap(); - - Iterator iter = items.iterator(); - while (iter.hasNext()) { - FileItem item = iter.next(); - if (item.isFormField()) { - fields.put(item.getFieldName(), item.getString()); - } else { - fields.put(item.getFieldName(), item); - } + uplFile.write(destinationFile); + if (LAMSUploadServlet.log.isDebugEnabled()) { + LAMSUploadServlet.log.debug("Uploaded file to " + destinationFile.getAbsolutePath()); } - FileItem uplFile = (FileItem) fields.get("NewFile"); - if (uplFile == null) { - // form field name used by CKEditor 3.x - uplFile = (FileItem) fields.get("upload"); - } - String fileNameLong = uplFile.getName(); - fileNameLong = fileNameLong.replace('\\', '/'); - String[] pathParts = fileNameLong.split("/"); - String fileName = pathParts[pathParts.length - 1]; - - String nameWithoutExt = LAMSUploadServlet.getNameWithoutExtension(fileName); - String ext = getExtension(fileName); - File pathToSave = new File(validCurrentDirPath, fileName); - fileUrl = currentWebPath + '/' + fileName; - if (extIsAllowed(typeStr, ext)) { - int counter = 1; - newName = fileName; - while (pathToSave.exists()) { - newName = nameWithoutExt + "_" + counter + "." + ext; - fileUrl = currentWebPath + '/' + newName; - returnMessage = "A file with the same name is already available. The uploaded file has been renamed to: " - + newName; - pathToSave = new File(validCurrentDirPath, newName); - counter++; - } - uplFile.write(pathToSave); - } else { - returnMessage = "Invalid file type"; - } - } catch (Exception e) { - LAMSUploadServlet.log.error(e); - returnMessage = "Error while uploading file"; + } else { + returnMessage = "Invalid file type"; } - } else { - returnMessage = "This file uploader is disabled. Please check the WEB-INF/web.xml file"; + } catch (Exception e) { + LAMSUploadServlet.log.error(e); + returnMessage = "Error while uploading file"; } } @@ -241,46 +180,31 @@ out.println(""); out.flush(); out.close(); - } else if (LAMSUploadServlet.debug) { + } else if (LAMSUploadServlet.log.isDebugEnabled()) { LAMSUploadServlet.log .debug("No CKEditor method found to run after completion, but upload finished with message: " + returnMessage); } - if (LAMSUploadServlet.debug) { + if (LAMSUploadServlet.log.isDebugEnabled()) { LAMSUploadServlet.log.debug("Upload finished"); } } - /* - * This method was fixed after Kris Barnhoorn (kurioskronic) submitted SF bug #991489 - */ - private static String getNameWithoutExtension(String fileName) { - return fileName.substring(0, fileName.lastIndexOf(".")); - } - - /* - * This method was fixed after Kris Barnhoorn (kurioskronic) submitted SF bug #991489 - */ - private String getExtension(String fileName) { - return fileName.substring(fileName.lastIndexOf(".") + 1); - } - /** * Helper function to convert the configuration string to an ArrayList. */ private ArrayList stringToArrayList(String str) { - - if (LAMSUploadServlet.debug) { + if (LAMSUploadServlet.log.isDebugEnabled()) { LAMSUploadServlet.log.debug(str); } String[] strArr = str.split("\\|"); ArrayList tmp = new ArrayList(); if (str.length() > 0) { for (int i = 0; i < strArr.length; ++i) { - if (LAMSUploadServlet.debug) { + if (LAMSUploadServlet.log.isDebugEnabled()) { LAMSUploadServlet.log.debug(i + " - " + strArr[i]); } tmp.add(strArr[i].toLowerCase()); @@ -294,7 +218,6 @@ */ private boolean extIsAllowed(String fileType, String ext) { - String extLower = ext.toLowerCase(); ArrayList allowList = LAMSUploadServlet.allowedExtensions.get(fileType); @@ -310,10 +233,4 @@ return false; } - - private void getConfigKeyValues() { - realBaseDir = Configuration.get(ConfigurationKeys.LAMS_EAR_DIR) + File.separator + FileUtil.LAMS_WWW_DIR - + File.separator + LAMSUploadServlet.baseDir; - lamsContextPath = "/" + Configuration.get(ConfigurationKeys.SERVER_URL_CONTEXT_PATH) + "/"; - } } \ No newline at end of file Index: lams_central/src/java/org/lamsfoundation/lams/web/QuestionsAction.java =================================================================== diff -u -rc6d1e011ff92ac2a8b0581efa0982100101c70b7 -r0dbc1d60bc9b43c26c431c9a2e15981ca0863d46 --- lams_central/src/java/org/lamsfoundation/lams/web/QuestionsAction.java (.../QuestionsAction.java) (revision c6d1e011ff92ac2a8b0581efa0982100101c70b7) +++ lams_central/src/java/org/lamsfoundation/lams/web/QuestionsAction.java (.../QuestionsAction.java) (revision 0dbc1d60bc9b43c26c431c9a2e15981ca0863d46) @@ -76,9 +76,8 @@ Collections.addAll(limitType, limitTypeParam.split(",")); } - Question[] questions = packageName.endsWith(".xml") ? QuestionParser - .parseQTIFile(uploadedFileStream, limitType) : QuestionParser.parseQTIPackage(uploadedFileStream, - limitType); + Question[] questions = packageName.endsWith(".xml") ? QuestionParser.parseQTIFile(uploadedFileStream, null, + limitType) : QuestionParser.parseQTIPackage(uploadedFileStream, limitType); request.setAttribute("questions", questions); return mapping.findForward("questionChoice"); Index: lams_central/web/questionChoice.jsp =================================================================== diff -u -ra43256ee6435f1cd14f46c235e4d507957a86a5b -r0dbc1d60bc9b43c26c431c9a2e15981ca0863d46 --- lams_central/web/questionChoice.jsp (.../questionChoice.jsp) (revision a43256ee6435f1cd14f46c235e4d507957a86a5b) +++ lams_central/web/questionChoice.jsp (.../questionChoice.jsp) (revision 0dbc1d60bc9b43c26c431c9a2e15981ca0863d46) @@ -23,6 +23,7 @@ .questionText { margin-left: 43px; + overflow: auto; } div.answerDiv input { @@ -88,6 +89,7 @@ answerDiv.toggle('slow'); } $('input', answerDiv).add(selector + 'feedback').add(selector + 'type').add(selector + 'text') + .add(selector + 'resourcesFolder') .attr('disabled', checked ? null : 'disabled'); if (checked) { @@ -161,18 +163,23 @@ () -
+ -
+
${question.text}

<%-- Question feedback --%> + <%-- If question contains images, where to take them from --%> + <%-- Answers, if required and exist --%>
@@ -184,7 +191,7 @@
+ type="checkbox" checked="checked" disabled="disabled" />${answer.text}
<%-- Do not display answers if management is too difficult or pointless --%> @@ -197,7 +204,7 @@ + value="" disabled="disabled" /> answers; private List matchAnswers; private Map matchMap; + private String resourcesFolderPath; public String getType() { return type; @@ -60,11 +61,11 @@ } public String getTitle() { - return title; + return title; } public void setTitle(String title) { - this.title = title; + this.title = title; } public String getText() { @@ -107,6 +108,14 @@ this.matchMap = matchMap; } + public String getResourcesFolderPath() { + return resourcesFolderPath; + } + + public void setResourcesFolderPath(String resourcesFolderPath) { + this.resourcesFolderPath = resourcesFolderPath; + } + @Override public int hashCode() { return new HashCodeBuilder().append(text).toHashCode(); Index: lams_common/src/java/org/lamsfoundation/lams/questions/QuestionParser.java =================================================================== diff -u -rc6d1e011ff92ac2a8b0581efa0982100101c70b7 -r0dbc1d60bc9b43c26c431c9a2e15981ca0863d46 --- lams_common/src/java/org/lamsfoundation/lams/questions/QuestionParser.java (.../QuestionParser.java) (revision c6d1e011ff92ac2a8b0581efa0982100101c70b7) +++ lams_common/src/java/org/lamsfoundation/lams/questions/QuestionParser.java (.../QuestionParser.java) (revision 0dbc1d60bc9b43c26c431c9a2e15981ca0863d46) @@ -36,13 +36,17 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import org.lamsfoundation.lams.util.UploadFileUtil; import org.lamsfoundation.lams.util.WebUtil; import org.lamsfoundation.lams.util.zipfile.ZipFileUtil; import org.lamsfoundation.lams.util.zipfile.ZipFileUtilException; @@ -69,6 +73,7 @@ private static final Question[] QUESTION_ARRAY_TYPE = new Question[] {}; // can be anything private static final String TEMP_PACKAGE_NAME_PREFIX = "QTI_PACKAGE_"; + private static final Pattern IMAGE_PATTERN = Pattern.compile("\\[IMAGE: (.*)\\]"); /** * Extracts questions from IMS QTI zip file. @@ -90,7 +95,7 @@ FileInputStream xmlFileStream = new FileInputStream(resourceFile); Question[] fileQuestions = null; try { - fileQuestions = QuestionParser.parseQTIFile(xmlFileStream, limitType); + fileQuestions = QuestionParser.parseQTIFile(xmlFileStream, tempPackageDirPath, limitType); } finally { xmlFileStream.close(); } @@ -102,7 +107,21 @@ } finally { // clean up packageFileStream.close(); - ZipFileUtil.deleteDirectory(tempPackageDirPath); + + // if there are any images attached, do not delete the exploded ZIP + // unfortunately, in this case it stays there until OS does temp dir clean up + boolean tempFolderStillNeeded = false; + if (result != null) { + for (Question question : result) { + if (!StringUtils.isBlank(question.getResourcesFolderPath())) { + tempFolderStillNeeded = true; + break; + } + } + } + if (!tempFolderStillNeeded) { + ZipFileUtil.deleteDirectory(tempPackageDirPath); + } } return result.toArray(QuestionParser.QUESTION_ARRAY_TYPE); @@ -111,7 +130,7 @@ /** * Extracts questions from IMS QTI xml file. */ - public static Question[] parseQTIFile(InputStream xmlFileStream, Set limitType) + public static Question[] parseQTIFile(InputStream xmlFileStream, String resourcesFolderPath, Set limitType) throws ParserConfigurationException, SAXException, IOException { List result = new ArrayList(); DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); @@ -144,14 +163,13 @@ Node presentationChild = presentationChildrenList.item(presentationChildIndex); // here is where question data is stored if ("material".equals(presentationChild.getNodeName())) { - Element questionElement = (Element) ((Element) presentationChild).getElementsByTagName("mattext") - .item(0); - String questionText = ((CDATASection) questionElement.getChildNodes().item(0)).getData(); + String questionText = QuestionParser.parseMaterialElement(presentationChild, question, + resourcesFolderPath); if (questionText.trim().startsWith("