diff --git a/pom.xml b/pom.xml index 0ccba6f8b19be53bf840657e4678b9cab1b3fea7..2cf4175b96fb0c966c0fd33e57d1992576e7b58a 100644 --- a/pom.xml +++ b/pom.xml @@ -1826,7 +1826,7 @@ <dependency> <groupId>org.openolat.imscp</groupId> <artifactId>manifest</artifactId> - <version>1.4.3</version> + <version>1.4.4</version> </dependency> <dependency> <groupId>com.rometools</groupId> diff --git a/src/main/java/org/olat/core/util/FileUtils.java b/src/main/java/org/olat/core/util/FileUtils.java index 58cba9304f2615cc9512bc3c2b8a932add2c2466..414630b439bc4cab39a55a1cf140f31fcda62f9f 100644 --- a/src/main/java/org/olat/core/util/FileUtils.java +++ b/src/main/java/org/olat/core/util/FileUtils.java @@ -30,6 +30,7 @@ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; @@ -50,9 +51,9 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.logging.log4j.Logger; import org.olat.core.logging.AssertException; import org.olat.core.logging.OLATRuntimeException; -import org.apache.logging.log4j.Logger; import org.olat.core.logging.Tracing; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; @@ -269,20 +270,19 @@ public class FileUtils { * @return true upon success */ public static long getDirSize(File path) { - Iterator<File> path_iterator; - File current_file; - long size; - File[] f = path.listFiles(); - if (f == null) { return 0; } - path_iterator = (Arrays.asList(f)).iterator(); - size = 0; - while (path_iterator.hasNext()) { - current_file = path_iterator.next(); - if (current_file.isFile()) { - size += current_file.length(); + if (f == null) { + return 0; + } + + Iterator<File> pathIterator = (Arrays.asList(f)).iterator(); + long size = 0l; + while (pathIterator.hasNext()) { + File currentFile = pathIterator.next(); + if (currentFile.isFile()) { + size += currentFile.length(); } else { - size += getDirSize(current_file); + size += getDirSize(currentFile); } } return size; @@ -746,30 +746,16 @@ public class FileUtils { } /** - * @param is the inputstream to close, may also be null + * @param cl The closeable to close, may also be null */ - public static void closeSafely(InputStream is) { - if (is == null) return; + public static void closeSafely(Closeable cl) { + if (cl == null) return; try { - is.close(); + cl.close(); } catch (IOException e) { // nothing to do } - } - - /** - * @param os the outputstream to close, may also be null - */ - public static void closeSafely(OutputStream os) { - if (os == null) return; - try { - os.close(); - } catch (IOException e) { - // nothing to do - } - - } /** * Extract file suffix. E.g. 'html' from index.html diff --git a/src/main/java/org/olat/ims/qti/qpool/QTIImportProcessor.java b/src/main/java/org/olat/ims/qti/qpool/QTIImportProcessor.java index c45f7c354a0b668694d369acdfb8e27a8a2fa9dc..1365a3cbc6ed2d775b1e9933993596e5890a8c68 100644 --- a/src/main/java/org/olat/ims/qti/qpool/QTIImportProcessor.java +++ b/src/main/java/org/olat/ims/qti/qpool/QTIImportProcessor.java @@ -19,7 +19,6 @@ */ package org.olat.ims.qti.qpool; -import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.Closeable; import java.io.File; @@ -31,7 +30,6 @@ import java.io.StringReader; import java.nio.file.FileSystems; 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; @@ -46,6 +44,7 @@ import org.apache.commons.io.IOUtils; import org.apache.logging.log4j.Logger; import org.dom4j.Attribute; import org.dom4j.Document; +import org.dom4j.DocumentException; import org.dom4j.DocumentFactory; import org.dom4j.Element; import org.dom4j.Node; @@ -85,7 +84,6 @@ import org.olat.modules.qpool.model.QuestionItemImpl; import org.olat.modules.taxonomy.TaxonomyLevel; import org.springframework.beans.factory.annotation.Autowired; import org.xml.sax.InputSource; -import org.xml.sax.SAXException; import nu.validator.htmlparser.common.XmlViolationPolicy; import nu.validator.htmlparser.sax.HtmlParser; @@ -145,7 +143,7 @@ class QTIImportProcessor { } for(DocInfos docInfos:docInfoList) { - IOUtils.closeQuietly(docInfos); + FileUtils.closeSafely(docInfos); } } } catch (IOException e) { @@ -440,7 +438,7 @@ class QTIImportProcessor { //write try { - OutputStream os = endFile.getOutputStream(false);; + OutputStream os = endFile.getOutputStream(false); XMLWriter xw = new XMLWriter(os, new OutputFormat(" ", true)); xw.write(itemDoc.getRootElement()); xw.close(); @@ -458,37 +456,32 @@ class QTIImportProcessor { private void processAssessmentMaterials(Element itemEl, VFSContainer container) { List<String> materials = getMaterials(itemEl); - try { - InputStream in = new FileInputStream(importedFile); - ZipInputStream zis = new ZipInputStream(in); + try(InputStream in = new FileInputStream(importedFile); + ZipInputStream zis = new ZipInputStream(in)) { ZipEntry entry; - try { - while ((entry = zis.getNextEntry()) != null) { - String name = entry.getName(); - if(materials.contains(name)) { - - VFSLeaf leaf = container.createChildLeaf(name); - OutputStream out = leaf.getOutputStream(false); - BufferedOutputStream bos = new BufferedOutputStream (out); - FileUtils.cpio(new BufferedInputStream(zis), bos, "unzip:"+entry.getName()); - bos.flush(); - bos.close(); - out.close(); - } + while ((entry = zis.getNextEntry()) != null) { + String name = entry.getName(); + if(materials.contains(name)) { + unzipMaterial(zis, container, name); } - } catch(Exception e) { - log.error("", e); - } finally { - IOUtils.closeQuietly(zis); - IOUtils.closeQuietly(in); } } catch (IOException e) { log.error("", e); } } - @SuppressWarnings("unchecked") + private void unzipMaterial(ZipInputStream zis, VFSContainer container, String name) { + VFSLeaf leaf = container.createChildLeaf(name); + try(OutputStream out = leaf.getOutputStream(false); + OutputStream bos = new BufferedOutputStream(out);) { + FileUtils.cpio(zis, bos, "unzip:" + name); + bos.flush(); + } catch (IOException e) { + log.error("", e); + } + } + protected List<String> getMaterials(Element el) { List<String> materialPath = new ArrayList<>(); //mattext @@ -530,10 +523,6 @@ class QTIImportProcessor { QTI12HtmlHandler contentHandler = new QTI12HtmlHandler(materialPath); parser.setContentHandler(contentHandler); parser.parse(new InputSource(new StringReader(content))); - } catch (SAXException e) { - log.error("", e); - } catch (IOException e) { - log.error("", e); } catch (Exception e) { log.error("", e); } @@ -563,44 +552,41 @@ class QTIImportProcessor { ZipUtil.unzipStrict(importedFile, container); } else { VFSLeaf endFile = container.createChildLeaf(rootFilename); - - OutputStream out = null; - FileInputStream in = null; - try { - out = endFile.getOutputStream(false); - in = new FileInputStream(importedFile); + try(OutputStream out = endFile.getOutputStream(false); + FileInputStream in = new FileInputStream(importedFile)) { IOUtils.copy(in, out); } catch (IOException e) { log.error("", e); - } finally { - IOUtils.closeQuietly(out); - IOUtils.closeQuietly(in); } } } private boolean processSidecarMetadata(QuestionItemImpl item, DocInfos docInfos) { - InputStream metadataIn = null; try { Path path = docInfos.root; if(path != null && path.getFileName() != null) { Path metadata = path.resolve(path.getFileName().toString() + "_metadata.xml"); - metadataIn = Files.newInputStream(metadata); - SAXReader reader = new SAXReader(); - Document document = reader.read(metadataIn); - Element rootElement = document.getRootElement(); - QTIMetadataConverter enricher = new QTIMetadataConverter(rootElement, qItemTypeDao, qEduContextDao, qpoolService); - enricher.toQuestion(item); + Document document = readSidecarMetadata(metadata); + if(document != null) { + Element rootElement = document.getRootElement(); + QTIMetadataConverter enricher = new QTIMetadataConverter(rootElement, qItemTypeDao, qEduContextDao, qpoolService); + enricher.toQuestion(item); + } } return true; - } catch(NoSuchFileException e) { - //nothing to do - return true; } catch (Exception e) { log.error("", e); return false; - } finally { - IOUtils.closeQuietly(metadataIn); + } + } + + private Document readSidecarMetadata(Path metadata) { + try(InputStream metadataIn = Files.newInputStream(metadata)) { + SAXReader reader = new SAXReader(); + return reader.read(metadataIn); + } catch(IOException | DocumentException e) { + log.error("", e); + return null; } } @@ -658,7 +644,6 @@ class QTIImportProcessor { protected List<DocInfos> getDocInfos() throws IOException { List<DocInfos> doc; if(importedFilename.toLowerCase().endsWith(".zip")) { - //doc = traverseZip(importedFile); doc = traverseZip_nio(importedFile); } else { doc = Collections.singletonList(traverseFile(importedFile)); @@ -666,10 +651,9 @@ class QTIImportProcessor { return doc; } - private DocInfos traverseFile(File file) throws IOException { - InputStream in = new FileInputStream(file); + private DocInfos traverseFile(File file) { try { - Document doc = readXml(in); + Document doc = readXml(file.toPath()); if(doc != null) { DocInfos d = new DocInfos(); d.doc = doc; @@ -680,41 +664,9 @@ class QTIImportProcessor { } catch(Exception e) { log.error("", e); return null; - } finally { - IOUtils.closeQuietly(in); } } - /* - private List<DocInfos> traverseZip(File file) throws IOException { - InputStream in = new FileInputStream(file); - ZipInputStream zis = new ZipInputStream(in); - List<DocInfos> docInfos = new ArrayList<>(); - - ZipEntry entry; - try { - while ((entry = zis.getNextEntry()) != null) { - String name = entry.getName(); - if(name != null && name.toLowerCase().endsWith(".xml")) { - Document doc = readXml(new ShieldInputStream(zis)); - if(doc != null) { - DocInfos d = new DocInfos(); - d.doc = doc; - d.filename = name; - docInfos.add(d); - } - } - } - } catch(Exception e) { - log.error("", e); - } finally { - IOUtils.closeQuietly(zis); - IOUtils.closeQuietly(in); - } - return docInfos; - } - */ - private List<DocInfos> traverseZip_nio(File file) throws IOException { List<DocInfos> docInfos = new ArrayList<>(); @@ -725,9 +677,7 @@ class QTIImportProcessor { List<Path> xmlFiles = visitor.getXmlFiles(); for(Path xmlFile:xmlFiles) { - InputStream in = Files.newInputStream(xmlFile); - - Document doc = readXml(in); + Document doc = readXml(xmlFile); if(doc != null) { DocInfos d = new DocInfos(); d.setDocument(doc); @@ -762,9 +712,9 @@ class QTIImportProcessor { } } - private Document readXml(InputStream in) { + private Document readXml(Path xmlFile) { Document doc = null; - try { + try(InputStream in = Files.newInputStream(xmlFile)) { XMLParser xmlParser = new XMLParser(new IMSEntityResolver()); doc = xmlParser.parse(in, false); return doc; diff --git a/src/main/java/org/olat/ims/qti/qpool/QTIMetadataConverter.java b/src/main/java/org/olat/ims/qti/qpool/QTIMetadataConverter.java index df8de04cf146dbb9bbcaf53de5d63cfe8b1a32ea..8f3e15fe2a801a7a3c50087fda62cb62cc77bf2c 100644 --- a/src/main/java/org/olat/ims/qti/qpool/QTIMetadataConverter.java +++ b/src/main/java/org/olat/ims/qti/qpool/QTIMetadataConverter.java @@ -130,7 +130,7 @@ public class QTIMetadataConverter { } TaxonomyLevel lowerLevel = null; - if(path != null && path.length > 0) { + if(path.length > 0) { for(String field :cleanedPath) { List<TaxonomyLevel> levels = qpoolService.getTaxonomyLevelBy(lowerLevel, field); @@ -248,6 +248,11 @@ public class QTIMetadataConverter { if(StringHelper.containsNonWhitespace(educationalContext)) { fullItem.setEducationalContext(toEducationalContext(educationalContext)); } + + String correctionTime = getMetadataEntry("oo_correction_time"); + if(StringHelper.containsNonWhitespace(correctionTime) && StringHelper.isLong(correctionTime)) { + fullItem.setCorrectionTime(toInteger(correctionTime)); + } } protected void toXml(QuestionItemFull fullItem) { @@ -273,10 +278,10 @@ public class QTIMetadataConverter { addMetadataField("status", fullItem.getQuestionStatus(), qtimetadata); addMetadataField("oo_std_dev_difficulty", fullItem.getStdevDifficulty(), qtimetadata); addMetadataField("oo_taxonomy", fullItem.getTaxonomicPath(), qtimetadata); - //fullItem.getTaxonomicLevel(); addMetadataField("title", fullItem.getTitle(), qtimetadata); addMetadataField("oo_topic", fullItem.getTopic(), qtimetadata); addMetadataField("oo_usage", fullItem.getUsage(), qtimetadata); + addMetadataField("oo_correction_time", fullItem.getCorrectionTime(), qtimetadata); } private void addMetadataField(String label, int entry, Element metadata) { @@ -331,7 +336,6 @@ public class QTIMetadataConverter { private String getMetadataEntry(String label) { String entry = null; - @SuppressWarnings("unchecked") List<Element> qtimetadatafields = qtimetadata.elements("qtimetadatafield"); for(Element qtimetadatafield:qtimetadatafields) { Element fieldlabel = qtimetadatafield.element("fieldlabel"); @@ -362,6 +366,14 @@ public class QTIMetadataConverter { } } + private Integer toInteger(String str) { + try { + return Integer.parseInt(str); + } catch (NumberFormatException e) { + return null; + } + } + private boolean validStatus(String str) { try { QuestionStatus.valueOf(str); diff --git a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemMetadata.java b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemMetadata.java index 1d2ca535ee4472156d70715c575f5f94b4e568d1..b9d8717e048d24bfa9d6055c4bc43a4d1b077c43 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemMetadata.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemMetadata.java @@ -53,6 +53,7 @@ public class AssessmentItemMetadata { private BigDecimal difficulty; private BigDecimal differentiation; private BigDecimal stdevDifficulty; + private Integer correctionTime; private boolean hasError; @@ -227,6 +228,14 @@ public class AssessmentItemMetadata { this.additionalInformations = additionalInformations; } + public Integer getCorrectionTime() { + return correctionTime; + } + + public void setCorrectionTime(Integer correctionTime) { + this.correctionTime = correctionTime; + } + public void toBuilder(ManifestMetadataBuilder metadata, Locale locale) { if(getQuestionType() != null) { metadata.setOpenOLATMetadataQuestionType(getQuestionType().getPrefix()); @@ -283,6 +292,7 @@ public class AssessmentItemMetadata { metadata.setOpenOLATMetadataTopic(topic); metadata.setOpenOLATMetadataAssessmentType(assessmentType); metadata.setOpenOLATMetadataAdditionalInformations(additionalInformations); + metadata.setOpenOLATMetadataCorrectionTime(correctionTime); } public void fromBuilder(ManifestMetadataBuilder metadata) { @@ -341,6 +351,9 @@ public class AssessmentItemMetadata { if(openolatMetadata.getAdditionalInformations() != null) { additionalInformations = openolatMetadata.getAdditionalInformations(); } + if(openolatMetadata.getCorrectionTime() != null) { + correctionTime = openolatMetadata.getCorrectionTime(); + } } } } \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/model/xml/ManifestBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/ManifestBuilder.java index 16aee5afb7770daef8a1da8c279cb49ab5760063..4fea39e63532a3199a06d50e046631bfd1d6e551 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/ManifestBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/ManifestBuilder.java @@ -20,11 +20,12 @@ package org.olat.ims.qti21.model.xml; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; import java.util.UUID; @@ -303,22 +304,15 @@ public class ManifestBuilder { } public static final ManifestBuilder read(File file) { - try(InputStream in = new FileInputStream(file )) { - ManifestType manifest = (ManifestType)((JAXBElement<?>)context - .createUnmarshaller().unmarshal(in)).getValue(); - return new ManifestBuilder(manifest); - } catch (JAXBException | IOException e) { - log.error("", e); - return null; - } + return read(file.toPath()); } - public static final ManifestBuilder read(InputStream in) { - try { + public static final ManifestBuilder read(Path file) { + try(InputStream in = Files.newInputStream(file)) { ManifestType manifest = (ManifestType)((JAXBElement<?>)context .createUnmarshaller().unmarshal(in)).getValue(); return new ManifestBuilder(manifest); - } catch (JAXBException e) { + } catch (JAXBException | IOException e) { log.error("", e); return null; } diff --git a/src/main/java/org/olat/ims/qti21/model/xml/ManifestMetadataBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/ManifestMetadataBuilder.java index a48fbb2703c96b886ea2dd9593658240f7afae33..fbd7fd9fe198e06cb9e63ca56693a2de850da7f1 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/ManifestMetadataBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/ManifestMetadataBuilder.java @@ -723,6 +723,10 @@ public class ManifestMetadataBuilder { getOpenOLATMetadata(true).setAdditionalInformations(informations); } + public void setOpenOLATMetadataCorrectionTime(Integer timeInMinute) { + getOpenOLATMetadata(true).setCorrectionTime(timeInMinute); + } + /** * Return the qti metadata if it exists or if specified, create * one and append it to the metadata of the resource. @@ -912,5 +916,6 @@ public class ManifestMetadataBuilder { setOpenOLATMetadataAssessmentType(item.getAssessmentType()); setOpenOLATMetadataTopic(item.getTopic()); setOpenOLATMetadataAdditionalInformations(item.getAdditionalInformations()); + setOpenOLATMetadataCorrectionTime(item.getCorrectionTime()); } } diff --git a/src/main/java/org/olat/ims/qti21/pool/QTI21ImportProcessor.java b/src/main/java/org/olat/ims/qti21/pool/QTI21ImportProcessor.java index f872dbe7df98ddaadd7068196e59744a66ade0af..c857c026064fe2f1e5c67ad780238e83e961259a 100644 --- a/src/main/java/org/olat/ims/qti21/pool/QTI21ImportProcessor.java +++ b/src/main/java/org/olat/ims/qti21/pool/QTI21ImportProcessor.java @@ -24,7 +24,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.Writer; import java.net.URI; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; @@ -42,13 +42,12 @@ import javax.xml.parsers.SAXParserFactory; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamWriter; +import org.apache.logging.log4j.Logger; import org.olat.core.CoreSpringFactory; import org.olat.core.id.Identity; -import org.apache.logging.log4j.Logger; import org.olat.core.logging.Tracing; import org.olat.core.util.PathUtils; import org.olat.core.util.StringHelper; -import org.olat.core.util.io.ShieldInputStream; import org.olat.fileresource.types.ImsQTI21Resource; import org.olat.ims.qti.qpool.QTIMetadataConverter; import org.olat.ims.qti21.QTI21Constants; @@ -127,8 +126,7 @@ public class QTI21ImportProcessor { List<Path> imsmanifests = visitor.getImsmanifestFiles(); for(Path imsmanifest:imsmanifests) { - InputStream in = Files.newInputStream(imsmanifest); - ManifestBuilder manifestBuilder = ManifestBuilder.read(new ShieldInputStream(in)); + ManifestBuilder manifestBuilder = ManifestBuilder.read(imsmanifest); List<ResourceType> resources = manifestBuilder.getResourceList(); for(ResourceType resource:resources) { ManifestMetadataBuilder metadataBuilder = manifestBuilder.getMetadataBuilder(resource, true); @@ -228,7 +226,7 @@ public class QTI21ImportProcessor { private void convertXmlFile(Path inputFile, Path outputFile, QTI21Infos infos) { try(InputStream in = Files.newInputStream(inputFile); - Writer out = Files.newBufferedWriter(outputFile, Charset.forName("UTF-8"))) { + Writer out = Files.newBufferedWriter(outputFile, StandardCharsets.UTF_8)) { XMLOutputFactory xof = XMLOutputFactory.newInstance(); XMLStreamWriter xtw = xof.createXMLStreamWriter(out); @@ -379,6 +377,7 @@ public class QTI21ImportProcessor { poolItem.setTopic(metadata.getTopic()); poolItem.setAssessmentType(metadata.getAssessmentType()); poolItem.setAdditionalInformations(metadata.getAdditionalInformations()); + poolItem.setCorrectionTime(metadata.getCorrectionTime()); } private void createLicense(QuestionItemImpl poolItem, AssessmentItemMetadata metadata) { diff --git a/src/main/java/org/olat/modules/qpool/QuestionItemShort.java b/src/main/java/org/olat/modules/qpool/QuestionItemShort.java index 6dc3d5478855c1835ed407c539185afd5e96f4f6..6361e0067dc7ccecbc6ab77a4d036c19740c0654 100644 --- a/src/main/java/org/olat/modules/qpool/QuestionItemShort.java +++ b/src/main/java/org/olat/modules/qpool/QuestionItemShort.java @@ -84,4 +84,7 @@ public interface QuestionItemShort extends OLATResourceable, CreateInfo, Modifie //technics public String getFormat(); + //management + public Integer getCorrectionTime(); + } diff --git a/src/main/java/org/olat/modules/qpool/manager/QuestionItemDAO.java b/src/main/java/org/olat/modules/qpool/manager/QuestionItemDAO.java index 71cab0a872b4f0421c85bff599e4106f75adca69..5b3d2922c2cb80bc2c24693bbfa2f48f2bf4352a 100644 --- a/src/main/java/org/olat/modules/qpool/manager/QuestionItemDAO.java +++ b/src/main/java/org/olat/modules/qpool/manager/QuestionItemDAO.java @@ -153,6 +153,9 @@ public class QuestionItemDAO { copy.setItemVersion(original.getItemVersion()); copy.setStatus(QuestionStatus.draft.name()); + // management + copy.setCorrectionTime(original.getCorrectionTime()); + //technical copy.setEditor(original.getEditor()); copy.setEditorVersion(original.getEditorVersion()); diff --git a/src/main/java/org/olat/modules/qpool/manager/QuestionItemDocumentFactory.java b/src/main/java/org/olat/modules/qpool/manager/QuestionItemDocumentFactory.java index 951961ba9f0be6b2ef14a2d6c1a800a3e4a52162..3d227a77779987276a34426c1f32f625db178786 100644 --- a/src/main/java/org/olat/modules/qpool/manager/QuestionItemDocumentFactory.java +++ b/src/main/java/org/olat/modules/qpool/manager/QuestionItemDocumentFactory.java @@ -153,7 +153,7 @@ public class QuestionItemDocumentFactory { ResourceLicense license = licenseService.loadLicense(item); if(license != null && license.getLicenseType() != null) { String licenseKey = String.valueOf(license.getLicenseType().getKey()); - addTextField(document, QItemDocument.LICENSE_TYPE_FIELD_NAME, licenseKey); + addTextField(document, AbstractOlatDocument.LICENSE_TYPE_FIELD_NAME, licenseKey); } //technical @@ -195,7 +195,7 @@ public class QuestionItemDocumentFactory { } TaxonomyLevel taxonomyLevel = item.getTaxonomyLevel(); if (taxonomyLevel != null) { - String materializedPathKeys = taxonomyLevel.getMaterializedPathKeys().replaceAll("/", "_"); + String materializedPathKeys = taxonomyLevel.getMaterializedPathKeys().replace("/", "_"); TextField field = new TextField(QItemDocument.TAXONOMIC_PATH_FIELD, materializedPathKeys, Field.Store.YES); document.add(field); } diff --git a/src/main/java/org/olat/modules/qpool/model/ItemWrapper.java b/src/main/java/org/olat/modules/qpool/model/ItemWrapper.java index 9c76e320ec4fb0afec99656ba819eb12039ee973..a75173196ae08a55325ddf2c730a2b6e2a9062c0 100644 --- a/src/main/java/org/olat/modules/qpool/model/ItemWrapper.java +++ b/src/main/java/org/olat/modules/qpool/model/ItemWrapper.java @@ -57,6 +57,8 @@ public class ItemWrapper implements QuestionItemView { private String educationalContextLevel; private String educationalLearningTime; + private Integer correctionTime; + private String itemType; private BigDecimal difficulty; private BigDecimal stdevDifficulty; @@ -247,7 +249,12 @@ public class ItemWrapper implements QuestionItemView { public int getUsage() { return usage; } - + + @Override + public Integer getCorrectionTime() { + return correctionTime; + } + @Override public Date getCreationDate() { return creationDate; @@ -348,6 +355,8 @@ public class ItemWrapper implements QuestionItemView { itemWrapper.educationalContextLevel = item.getEducationalContextLevel(); itemWrapper.educationalLearningTime = item.getEducationalLearningTime(); + itemWrapper.correctionTime = item.getCorrectionTime(); + itemWrapper.itemType = item.getItemType(); itemWrapper.difficulty = item.getDifficulty(); itemWrapper.stdevDifficulty = item.getStdevDifficulty(); @@ -368,7 +377,7 @@ public class ItemWrapper implements QuestionItemView { } public ItemWrapperBuilder setAuthor(Number authorCount) { - itemWrapper.isAuthor = authorCount == null ? false : authorCount.longValue() > 0; + itemWrapper.isAuthor = authorCount != null && authorCount.longValue() > 0; return this; } @@ -378,7 +387,7 @@ public class ItemWrapper implements QuestionItemView { } public ItemWrapperBuilder setTeacher(Number teacherCount) { - itemWrapper.isTeacher = teacherCount == null ? false : teacherCount.longValue() > 0; + itemWrapper.isTeacher = teacherCount != null && teacherCount.longValue() > 0; return this; } @@ -388,12 +397,12 @@ public class ItemWrapper implements QuestionItemView { } public ItemWrapperBuilder setManager(Number managerCount) { - itemWrapper.isManager = managerCount == null ? false : managerCount.longValue() > 0; + itemWrapper.isManager = managerCount != null && managerCount.longValue() > 0; return this; } public ItemWrapperBuilder setRater(Number ratingsCount) { - itemWrapper.isRater = ratingsCount == null ? false : ratingsCount.longValue() > 0; + itemWrapper.isRater = ratingsCount != null && ratingsCount.longValue() > 0; return this; } @@ -403,7 +412,7 @@ public class ItemWrapper implements QuestionItemView { } public ItemWrapperBuilder setEditableInPool(Number editableInPoolCount) { - itemWrapper.isEditableInPool = editableInPoolCount == null ? false : editableInPoolCount.longValue() > 0; + itemWrapper.isEditableInPool = editableInPoolCount != null && editableInPoolCount.longValue() > 0; return this; } @@ -413,7 +422,7 @@ public class ItemWrapper implements QuestionItemView { } public ItemWrapperBuilder setEditableInShare(Number editableInShareCount) { - itemWrapper.isEditableInShare = editableInShareCount == null ? false : editableInShareCount.longValue() > 0; + itemWrapper.isEditableInShare = editableInShareCount != null && editableInShareCount.longValue() > 0; return this; } @@ -423,7 +432,7 @@ public class ItemWrapper implements QuestionItemView { } public ItemWrapperBuilder setMarked(Number markedCount) { - itemWrapper.isMarked = markedCount == null ? false : markedCount.longValue() > 0; + itemWrapper.isMarked = markedCount != null && markedCount.longValue() > 0; return this; } @@ -438,9 +447,8 @@ public class ItemWrapper implements QuestionItemView { } public ItemWrapper create() { - log.debug("Question item wrapped:" + itemWrapper.toString()); + log.debug("Question item wrapped: {}", itemWrapper); return itemWrapper; } } - } \ No newline at end of file diff --git a/src/main/java/org/olat/modules/qpool/model/QuestionItemImpl.java b/src/main/java/org/olat/modules/qpool/model/QuestionItemImpl.java index f7976aeeb9d4c097c15a9bfdc839a2401b2139bb..94e8d2703c465e65c96fe6aed933107b0b66b2dd 100644 --- a/src/main/java/org/olat/modules/qpool/model/QuestionItemImpl.java +++ b/src/main/java/org/olat/modules/qpool/model/QuestionItemImpl.java @@ -120,6 +120,10 @@ public class QuestionItemImpl implements QuestionItemFull, Persistable { @Column(name="q_assessment_type", nullable=true, insertable=true, updatable=true) private String assessmentType; + //management + @Column(name="q_correction_time", nullable=true, insertable=true, updatable=true) + private Integer correctionTime; + //life cycle @Column(name="q_version", nullable=true, insertable=true, updatable=true) private String itemVersion; @@ -411,6 +415,15 @@ public class QuestionItemImpl implements QuestionItemFull, Persistable { this.status = status; } + @Override + public Integer getCorrectionTime() { + return correctionTime; + } + + public void setCorrectionTime(Integer correctionTime) { + this.correctionTime = correctionTime; + } + @Override public String getKeywords() { return keywords; diff --git a/src/main/java/org/olat/modules/qpool/ui/AbstractItemListController.java b/src/main/java/org/olat/modules/qpool/ui/AbstractItemListController.java index 9aa36b2a0b1fc17627e79f81f88001f7456fee60..cf3afdf59bb862e2ba6a852559ff596b945f4f3b 100644 --- a/src/main/java/org/olat/modules/qpool/ui/AbstractItemListController.java +++ b/src/main/java/org/olat/modules/qpool/ui/AbstractItemListController.java @@ -198,6 +198,7 @@ public abstract class AbstractItemListController extends FormBasicController columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.differentiation)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.numOfAnswerAlternatives)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.usage)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.correctionTime)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.type)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.format)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.rating)); diff --git a/src/main/java/org/olat/modules/qpool/ui/ItemRow.java b/src/main/java/org/olat/modules/qpool/ui/ItemRow.java index 3db090a14cb58935fa1fc30eda111fcfec903488..87fb4778c9fb521d0f2e055d6b830effad47ae95 100644 --- a/src/main/java/org/olat/modules/qpool/ui/ItemRow.java +++ b/src/main/java/org/olat/modules/qpool/ui/ItemRow.java @@ -212,6 +212,11 @@ public class ItemRow implements QuestionItemView { return delegate.getUsage(); } + @Override + public Integer getCorrectionTime() { + return delegate.getCorrectionTime(); + } + @Override public Date getCreationDate() { return delegate.getCreationDate(); diff --git a/src/main/java/org/olat/modules/qpool/ui/QuestionItemAuditLogExport.java b/src/main/java/org/olat/modules/qpool/ui/QuestionItemAuditLogExport.java index 670914e8facb71cc7c372e8cb7084341795b2e42..03221bf71e89a29107f127d1291c1f8f000f12ba 100644 --- a/src/main/java/org/olat/modules/qpool/ui/QuestionItemAuditLogExport.java +++ b/src/main/java/org/olat/modules/qpool/ui/QuestionItemAuditLogExport.java @@ -19,7 +19,6 @@ */ package org.olat.modules.qpool.ui; -import java.io.IOException; import java.io.OutputStream; import java.math.BigDecimal; import java.util.Collections; @@ -27,12 +26,12 @@ import java.util.Comparator; import java.util.Date; import java.util.List; +import org.apache.logging.log4j.Logger; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.services.license.License; import org.olat.core.commons.services.license.LicenseModule; import org.olat.core.commons.services.license.LicenseService; import org.olat.core.gui.translator.Translator; -import org.apache.logging.log4j.Logger; import org.olat.core.logging.Tracing; import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; @@ -99,8 +98,6 @@ public class QuestionItemAuditLogExport extends OpenXMLWorkbookResource { addSheetSettings(exportSheet); addHeader(exportSheet); addContent(exportSheet, workbook); - } catch (IOException e) { - log.error("", e); } catch (Exception e) { log.error("", e); } @@ -139,6 +136,7 @@ public class QuestionItemAuditLogExport extends OpenXMLWorkbookResource { headerRow.addCell(pos++, translator.translate("export.log.header.differentiation")); headerRow.addCell(pos++, translator.translate("export.log.header.numOfAnswerAlternatives")); headerRow.addCell(pos++, translator.translate("export.log.header.usage")); + headerRow.addCell(pos++, translator.translate("export.log.header.correctionTime")); headerRow.addCell(pos++, translator.translate("export.log.header.version")); headerRow.addCell(pos++, translator.translate("export.log.header.status")); if (licenseModule.isEnabled(licenseHandler)) { @@ -183,6 +181,7 @@ public class QuestionItemAuditLogExport extends OpenXMLWorkbookResource { row.addCell(pos++, format(item.getDifferentiation())); row.addCell(pos++, String.valueOf(item.getNumOfAnswerAlternatives())); row.addCell(pos++, String.valueOf(item.getUsage())); + row.addCell(pos++, item.getCorrectionTime(), null); row.addCell(pos++, item.getItemVersion()); row.addCell(pos++, getTranslatedStatus(item.getQuestionStatus())); } else { diff --git a/src/main/java/org/olat/modules/qpool/ui/QuestionItemDataModel.java b/src/main/java/org/olat/modules/qpool/ui/QuestionItemDataModel.java index d35e2c50d247aaac573cc1e015a0ad5e7c5a329e..a6517ec1580c41fd194f9b748da088d1d01449f0 100644 --- a/src/main/java/org/olat/modules/qpool/ui/QuestionItemDataModel.java +++ b/src/main/java/org/olat/modules/qpool/ui/QuestionItemDataModel.java @@ -97,6 +97,7 @@ public class QuestionItemDataModel extends DefaultFlexiTableDataSourceModel<Item return item.getNumOfAnswerAlternatives() > 0 ? Integer.toString(item.getNumOfAnswerAlternatives()) : ""; case usage: return item.getUsage() > 0 ? Integer.toString(item.getUsage()) : ""; + case correctionTime: return item.getCorrectionTime(); case type: { String type = item.getItemType(); if(type == null) { @@ -149,7 +150,8 @@ public class QuestionItemDataModel extends DefaultFlexiTableDataSourceModel<Item statusLastModified("lifecycle.status.last.modified"), license("rights.license"), editable("editable"), - mark("mark"); + mark("mark"), + correctionTime("question.correctionTime"); private final String i18nKey; diff --git a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties index 93a2c38898d8eb1db0d59127296f837df4939c68..255f4dcfb9fb79e3faad5a863eb9d3cdc55d65de 100644 --- a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties @@ -79,6 +79,7 @@ export.log=Log export.log.header.additional.informations=$\:general.additional.informations export.log.header.assessment.type=$\:question.assessmentType export.log.header.context=$\:educational.context +export.log.header.correctionTime=$\:question.correctionTime export.log.header.coverage=$\:general.coverage export.log.header.differentiation=$\:question.differentiation export.log.header.difficulty=$\:question.difficulty @@ -231,6 +232,7 @@ question.assessmentType=Testart question.assessmentType.both=Both question.assessmentType.formative=Formative question.assessmentType.summative=Summative +question.correctionTime=Ben\u00F6tigte manuelle Korrekturszeit (Minuten) question.differentiation=Trennsch\u00E4rfe question.differentiation.example=Wert zwischen -1.0 und 1.0, zum Beispiel 0.1 question.difficulty=Itemschwierigkeit diff --git a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties index 1045cc6a1e70ef815adc4ca46a46244f840710e3..5530355799b81d24591702ce4b54a28a2ea6e964 100644 --- a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties @@ -79,6 +79,7 @@ export.log=Log export.log.header.additional.informations=$\:general.additional.informations export.log.header.assessment.type=$\:question.assessmentType export.log.header.context=$\:educational.context +export.log.header.correctionTime=$\:question.correctionTime export.log.header.coverage=$\:general.coverage export.log.header.differentiation=$\:question.differentiation export.log.header.difficulty=$\:question.difficulty @@ -231,6 +232,7 @@ question.assessmentType=Test type question.assessmentType.both=Both question.assessmentType.formative=Formative question.assessmentType.summative=Summative +question.correctionTime=Requited manual grading time (minutes) question.differentiation=Discrimination index question.differentiation.example=Value between -1.0 and 1.0. Example\: 0.1 question.difficulty=Difficulty index diff --git a/src/main/java/org/olat/modules/qpool/ui/metadata/QuestionMetadataEditController.java b/src/main/java/org/olat/modules/qpool/ui/metadata/QuestionMetadataEditController.java index cc6c8b0a1a55deef7ac4b97966188e4100528491..b971e57d03cf80cdc5a0f0bb372a6d317f9ba16b 100644 --- a/src/main/java/org/olat/modules/qpool/ui/metadata/QuestionMetadataEditController.java +++ b/src/main/java/org/olat/modules/qpool/ui/metadata/QuestionMetadataEditController.java @@ -38,6 +38,7 @@ import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; +import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.modules.qpool.MetadataSecurityCallback; import org.olat.modules.qpool.QPoolService; @@ -70,6 +71,7 @@ public class QuestionMetadataEditController extends FormBasicController { private TextElement differentiationEl; private TextElement numAnswerAltEl; private TextElement usageEl; + private TextElement correctionTimeMinuteElement; private FormLayoutContainer buttonsCont; private QuestionItem item; @@ -161,7 +163,12 @@ public class QuestionMetadataEditController extends FormBasicController { usageEl = uifactory.addTextElement("question.usage", "question.usage", 24, numUsage, formLayout); usageEl.setElementCssClass("o_sel_usage"); usageEl.setDisplaySize(4); - + + String correctionTime = item.getCorrectionTime() == null ? "" : item.getCorrectionTime().toString(); + correctionTimeMinuteElement = uifactory.addTextElement("question.correctionTime", 8, correctionTime, formLayout); + correctionTimeMinuteElement.setElementCssClass("o_sel_correction_time"); + correctionTimeMinuteElement.setDisplaySize(4); + buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); buttonsCont.setElementCssClass("o_sel_qpool_metadata_buttons"); buttonsCont.setRootForm(mainForm); @@ -205,6 +212,7 @@ public class QuestionMetadataEditController extends FormBasicController { allOk &= validateBigDecimal(differentiationEl, -1.0d, 1.0d, true); allOk &= validateInteger(numAnswerAltEl, 0, Integer.MAX_VALUE, true); allOk &= validateInteger(usageEl, 0, Integer.MAX_VALUE, true); + allOk &= validateInteger(correctionTimeMinuteElement, 0, Integer.MAX_VALUE, true); return allOk; } @@ -242,6 +250,11 @@ public class QuestionMetadataEditController extends FormBasicController { int numUsage = toInt(usageEl.getValue()); itemImpl.setUsage(numUsage); + + if(StringHelper.containsNonWhitespace(correctionTimeMinuteElement.getValue()) + && StringHelper.isLong(correctionTimeMinuteElement.getValue())) { + itemImpl.setCorrectionTime(Integer.valueOf(correctionTimeMinuteElement.getValue())); + } item = qpoolService.updateItem(itemImpl); builder.withAfter(item); diff --git a/src/main/resources/database/mysql/alter_14_1_x_to_14_2_0.sql b/src/main/resources/database/mysql/alter_14_1_x_to_14_2_0.sql index 544d7b50c7ad476c75bb4735019b85b801201a24..6de790bfa5b01b2938599e3037fb4a4b7d7503fb 100644 --- a/src/main/resources/database/mysql/alter_14_1_x_to_14_2_0.sql +++ b/src/main/resources/database/mysql/alter_14_1_x_to_14_2_0.sql @@ -24,3 +24,7 @@ alter table o_noti_sub add column subenabled bit default 1; -- index create index mark_all_idx on o_mark(resname,resid,creator_id); create index idx_eff_stat_course_ident_idx on o_as_eff_statement (fk_identity,course_repo_key); + +-- question pool +alter table o_qp_item add column q_correction_time bigint default null; + diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql index 914261fb98ae83af61aa5728a7fd7361fa0cac67..7c05dd24ad558c1ded741ea79ef0c08d4abdc262 100644 --- a/src/main/resources/database/mysql/setupDatabase.sql +++ b/src/main/resources/database/mysql/setupDatabase.sql @@ -1650,6 +1650,7 @@ create table o_qp_item ( q_differentiation decimal(10,9), q_num_of_answers_alt bigint not null default 0, q_usage bigint not null default 0, + q_correction_time bigint default null, q_assessment_type varchar(64), q_status varchar(32) not null, q_version varchar(50), diff --git a/src/main/resources/database/oracle/alter_14_1_x_to_14_2_0.sql b/src/main/resources/database/oracle/alter_14_1_x_to_14_2_0.sql index 8c5828838bb804f548997d61aa13d2fbfd230c76..cd0b42f81b4db7fe165e90c6b64b706272808490 100644 --- a/src/main/resources/database/oracle/alter_14_1_x_to_14_2_0.sql +++ b/src/main/resources/database/oracle/alter_14_1_x_to_14_2_0.sql @@ -26,3 +26,5 @@ alter table o_noti_sub add subenabled number default 1; create index mark_all_idx on o_mark(resname,resid,creator_id); create index idx_eff_stat_course_ident_idx on o_as_eff_statement (fk_identity,course_repo_key); +-- question pool +alter table o_qp_item add q_correction_time number(20) default null; diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql index 0860673c0639800e21e18c36abe5b360cfabeadf..cdcce51147a2e3bb9357f9121c4cf86395473543 100644 --- a/src/main/resources/database/oracle/setupDatabase.sql +++ b/src/main/resources/database/oracle/setupDatabase.sql @@ -2210,6 +2210,7 @@ create table o_qp_item ( q_differentiation decimal(10,9), q_num_of_answers_alt number(20) default 0 not null, q_usage number(20) default 0 not null, + q_correction_time number(20) default null, q_assessment_type varchar2(64 char), q_status varchar2(32 char) not null, q_version varchar2(50 char), diff --git a/src/main/resources/database/postgresql/alter_14_1_x_to_14_2_0.sql b/src/main/resources/database/postgresql/alter_14_1_x_to_14_2_0.sql index 50f3fff6f9bf367b7602f1579fd8e802fc089ff4..59e40c347e7ee91bec9db04793bf239ddd412ef9 100644 --- a/src/main/resources/database/postgresql/alter_14_1_x_to_14_2_0.sql +++ b/src/main/resources/database/postgresql/alter_14_1_x_to_14_2_0.sql @@ -28,3 +28,7 @@ alter table o_noti_sub add column subenabled bool default true; -- index create index mark_all_idx on o_mark(resname,resid,creator_id); create index idx_eff_stat_course_ident_idx on o_as_eff_statement (fk_identity,course_repo_key); + +-- question pool +alter table o_qp_item add column q_correction_time int8 default null; + diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql index e4f9d3225edd9d74b18dedb159e8d40c5ae9a897..63905caeb91e05553bcb3d0b3a9879b67875bef2 100644 --- a/src/main/resources/database/postgresql/setupDatabase.sql +++ b/src/main/resources/database/postgresql/setupDatabase.sql @@ -2173,6 +2173,7 @@ create table o_qp_item ( q_differentiation decimal(10,9), q_num_of_answers_alt int8 not null default 0, q_usage int8 not null default 0, + q_correction_time int8 default null, q_assessment_type varchar(64), q_status varchar(32) not null, q_version varchar(50), diff --git a/src/test/java/org/olat/ims/qti/qpool/QTIExportProcessorTest.java b/src/test/java/org/olat/ims/qti/qpool/QTIExportProcessorTest.java index 60d87d43071330c5090db40316458bdca186fa99..c9ed1afbbb49234bcfae075298638da866d834ea 100644 --- a/src/test/java/org/olat/ims/qti/qpool/QTIExportProcessorTest.java +++ b/src/test/java/org/olat/ims/qti/qpool/QTIExportProcessorTest.java @@ -31,7 +31,6 @@ import java.util.Locale; import java.util.UUID; import java.util.zip.ZipOutputStream; -import org.apache.commons.io.IOUtils; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -89,8 +88,8 @@ public class QTIExportProcessorTest extends OlatTestCase { OutputStream out = new ByteArrayOutputStream(); ZipOutputStream zout = new ZipOutputStream(out); exportProc.assembleTest(fullItems, zout); - - IOUtils.closeQuietly(zout); - IOUtils.closeQuietly(out); + + zout.close(); + out.close(); } } \ No newline at end of file diff --git a/src/test/java/org/olat/ims/qti/qpool/QTIImportProcessorTest.java b/src/test/java/org/olat/ims/qti/qpool/QTIImportProcessorTest.java index d4339eae3212946dc8483e3d5a62aff6652f2ed4..3cc94892b758a105dbb534076b632a3b62c62c1e 100644 --- a/src/test/java/org/olat/ims/qti/qpool/QTIImportProcessorTest.java +++ b/src/test/java/org/olat/ims/qti/qpool/QTIImportProcessorTest.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Locale; import java.util.UUID; +import org.apache.logging.log4j.Logger; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.Node; @@ -37,6 +38,7 @@ import org.junit.Before; import org.junit.Test; import org.olat.core.commons.persistence.DB; import org.olat.core.id.Identity; +import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; @@ -70,6 +72,8 @@ import org.springframework.beans.factory.annotation.Autowired; */ public class QTIImportProcessorTest extends OlatTestCase { + private static final Logger log = Tracing.createLoggerFor(QTIImportProcessorTest.class); + private static Identity owner; @Autowired @@ -159,6 +163,8 @@ public class QTIImportProcessorTest extends OlatTestCase { Assert.assertTrue(qtiLeaf instanceof VFSLeaf); Assert.assertTrue(qtiLeaf.exists()); Assert.assertEquals(itemFile.length(), ((VFSLeaf)qtiLeaf).getSize()); + + docInfos.close(); } @Test @@ -216,6 +222,8 @@ public class QTIImportProcessorTest extends OlatTestCase { List<ItemInfos> itemElements = proc.getItemList(docInfos); Assert.assertNotNull(itemElements); Assert.assertEquals(4, itemElements.size()); + + docInfos.close(); } @Test @@ -272,10 +280,14 @@ public class QTIImportProcessorTest extends OlatTestCase { Assert.assertTrue(itemLeaf instanceof VFSLeaf); //try to parse it - InputStream is = ((VFSLeaf)itemLeaf).getInputStream(); - XMLParser xmlParser = new XMLParser(new IMSEntityResolver()); - Document doc = xmlParser.parse(is, false); - Node itemNode = doc.selectSingleNode("questestinterop/item"); + Node itemNode = null; + try(InputStream is = ((VFSLeaf)itemLeaf).getInputStream()) { + XMLParser xmlParser = new XMLParser(new IMSEntityResolver()); + Document doc = xmlParser.parse(is, false); + itemNode = doc.selectSingleNode("questestinterop/item"); + } catch(IOException e) { + log.error("", e); + } Assert.assertNotNull(itemNode); } } @@ -305,10 +317,14 @@ public class QTIImportProcessorTest extends OlatTestCase { Assert.assertTrue(itemLeaf instanceof VFSLeaf); //try to parse it - InputStream is = ((VFSLeaf)itemLeaf).getInputStream(); - XMLParser xmlParser = new XMLParser(new IMSEntityResolver()); - Document doc = xmlParser.parse(is, false); - Node itemNode = doc.selectSingleNode("questestinterop/item"); + Node itemNode = null; + try(InputStream is = ((VFSLeaf)itemLeaf).getInputStream()) { + XMLParser xmlParser = new XMLParser(new IMSEntityResolver()); + Document doc = xmlParser.parse(is, false); + itemNode = doc.selectSingleNode("questestinterop/item"); + } catch(IOException e) { + log.error("", e); + } Assert.assertNotNull(itemNode); //check the attachments @@ -351,10 +367,14 @@ public class QTIImportProcessorTest extends OlatTestCase { Assert.assertTrue(itemLeaf instanceof VFSLeaf); //try to parse it - InputStream is = ((VFSLeaf)itemLeaf).getInputStream(); - XMLParser xmlParser = new XMLParser(new IMSEntityResolver()); - Document doc = xmlParser.parse(is, false); - Node itemNode = doc.selectSingleNode("questestinterop/item"); + Node itemNode = null; + try(InputStream is = ((VFSLeaf)itemLeaf).getInputStream()) { + XMLParser xmlParser = new XMLParser(new IMSEntityResolver()); + Document doc = xmlParser.parse(is, false); + itemNode = doc.selectSingleNode("questestinterop/item"); + } catch(IOException e) { + log.error("", e); + } Assert.assertNotNull(itemNode); //check the attachments @@ -404,10 +424,14 @@ public class QTIImportProcessorTest extends OlatTestCase { Assert.assertTrue(itemLeaf instanceof VFSLeaf); //try to parse it - InputStream is = ((VFSLeaf)itemLeaf).getInputStream(); - XMLParser xmlParser = new XMLParser(new IMSEntityResolver()); - Document doc = xmlParser.parse(is, false); - Node itemNode = doc.selectSingleNode("questestinterop/item"); + Node itemNode = null; + try(InputStream is = ((VFSLeaf)itemLeaf).getInputStream()) { + XMLParser xmlParser = new XMLParser(new IMSEntityResolver()); + Document doc = xmlParser.parse(is, false); + itemNode = doc.selectSingleNode("questestinterop/item"); + } catch(IOException e) { + log.error("", e); + } Assert.assertNotNull(itemNode); //check the attachments @@ -487,6 +511,7 @@ public class QTIImportProcessorTest extends OlatTestCase { Assert.assertEquals("/Physique/Astronomie/Astrophysique/", item.getTaxonomicPath()); Assert.assertEquals("Une question sur Pluton", item.getTitle()); Assert.assertEquals(0, item.getUsage()); + Assert.assertEquals(Integer.valueOf(2), item.getCorrectionTime()); } @Test @@ -514,6 +539,8 @@ public class QTIImportProcessorTest extends OlatTestCase { Assert.assertNotNull(materials); Assert.assertEquals(1, materials.size()); Assert.assertEquals("media/filmH264.mp4", materials.get(0)); + + docInfos.close(); } private boolean exists(QuestionItemFull itemFull, String path) { diff --git a/src/test/java/org/olat/ims/qti/qpool/qitem_metadatas.zip b/src/test/java/org/olat/ims/qti/qpool/qitem_metadatas.zip index aa7abd90c694eea11c1dd5e5218462ea4ef99cb5..b5a0be721ccd3137505c2d785830c5be22df46d1 100644 Binary files a/src/test/java/org/olat/ims/qti/qpool/qitem_metadatas.zip and b/src/test/java/org/olat/ims/qti/qpool/qitem_metadatas.zip differ diff --git a/src/test/java/org/olat/ims/qti/statistics/manager/QTIStatisticsManagerLargeTest.java b/src/test/java/org/olat/ims/qti/statistics/manager/QTIStatisticsManagerLargeTest.java index 6843608d41ae3b5f1551511b6e5ed2e87981e095..b0431c92b1c4e350120b0db68d5559272c622503 100644 --- a/src/test/java/org/olat/ims/qti/statistics/manager/QTIStatisticsManagerLargeTest.java +++ b/src/test/java/org/olat/ims/qti/statistics/manager/QTIStatisticsManagerLargeTest.java @@ -22,6 +22,7 @@ package org.olat.ims.qti.statistics.manager; import static org.junit.Assert.assertNotNull; +import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Calendar; @@ -33,6 +34,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import org.apache.logging.log4j.Logger; import org.dom4j.Document; import org.dom4j.Element; import org.junit.Assert; @@ -41,7 +43,6 @@ import org.junit.Test; import org.olat.basesecurity.OrganisationService; import org.olat.core.commons.persistence.DB; import org.olat.core.id.Organisation; -import org.apache.logging.log4j.Logger; import org.olat.core.logging.Tracing; import org.olat.core.util.xml.XMLParser; import org.olat.ims.qti.QTIResult; @@ -328,20 +329,24 @@ public class QTIStatisticsManagerLargeTest extends OlatTestCase { } @SuppressWarnings("rawtypes") - private void getItemObjectList() { - InputStream in = QTIStatisticsManagerLargeTest.class.getResourceAsStream("qti.xml"); - XMLParser xmlParser = new XMLParser(new IMSEntityResolver()); - Document doc = xmlParser.parse(in, false); - Element root = doc.getRootElement(); - List items = root.selectNodes("//item"); - itemObjects = new ArrayList<>(); - for (Iterator iter = items.iterator(); iter.hasNext();) { - Element el_item = (Element) iter.next(); - if (el_item.selectNodes(".//response_lid").size() > 0) { - itemObjects.add(new ItemWithResponseLid(el_item)); - } else if (el_item.selectNodes(".//response_str").size() > 0) { - itemObjects.add(new ItemWithResponseStr(el_item)); + private void getItemObjectList() throws IOException { + try(InputStream in = QTIStatisticsManagerLargeTest.class.getResourceAsStream("qti.xml")) { + XMLParser xmlParser = new XMLParser(new IMSEntityResolver()); + Document doc = xmlParser.parse(in, false); + Element root = doc.getRootElement(); + List items = root.selectNodes("//item"); + itemObjects = new ArrayList<>(); + for (Iterator iter = items.iterator(); iter.hasNext();) { + Element el_item = (Element) iter.next(); + if (el_item.selectNodes(".//response_lid").size() > 0) { + itemObjects.add(new ItemWithResponseLid(el_item)); + } else if (el_item.selectNodes(".//response_str").size() > 0) { + itemObjects.add(new ItemWithResponseStr(el_item)); + } } + } catch(IOException e) { + log.error("", e); + throw e; } } diff --git a/src/test/java/org/olat/modules/qpool/manager/QuestionDAOTest.java b/src/test/java/org/olat/modules/qpool/manager/QuestionDAOTest.java index c6ec572b6b5d8b430e75ee12f1d6010bdd25c469..baf4251e78db351005c7c156db02dc196c2bcffd 100644 --- a/src/test/java/org/olat/modules/qpool/manager/QuestionDAOTest.java +++ b/src/test/java/org/olat/modules/qpool/manager/QuestionDAOTest.java @@ -150,6 +150,7 @@ public class QuestionDAOTest extends OlatTestCase { original.setNumOfAnswerAlternatives(4); original.setUsage(5); original.setAssessmentType("formative"); + original.setCorrectionTime(3); //lifecycle original.setItemVersion("1.0"); original.setStatus(QuestionStatus.review.name()); @@ -193,6 +194,7 @@ public class QuestionDAOTest extends OlatTestCase { Assert.assertEquals(original.getNumOfAnswerAlternatives(), clone.getNumOfAnswerAlternatives()); Assert.assertEquals(0, clone.getUsage()); Assert.assertEquals(original.getAssessmentType(), clone.getAssessmentType()); + Assert.assertEquals(Integer.valueOf(3), clone.getCorrectionTime()); //lifecycle Assert.assertEquals(QuestionStatus.draft.name(), clone.getStatus()); Assert.assertNotNull(clone.getQuestionStatusLastModified()); diff --git a/src/test/java/org/olat/selenium/QuestionPoolTest.java b/src/test/java/org/olat/selenium/QuestionPoolTest.java index d190bff7867c6f6b342c0f420da49c792bdef7d1..5229f2cbecec37304e38044df44b642ccfd6d1b7 100644 --- a/src/test/java/org/olat/selenium/QuestionPoolTest.java +++ b/src/test/java/org/olat/selenium/QuestionPoolTest.java @@ -277,7 +277,7 @@ public class QuestionPoolTest extends Deployments { .metadata() .openItemAnalyse() .setLearningTime(1, 5, 3, 35) - .setItemAnalyse(0.5d, 0.3d, -0.7d, 2, 3) + .setItemAnalyse(0.5d, 0.3d, -0.7d, 2, 3, 5) .saveItemAnalyse(); // open quick view @@ -292,7 +292,8 @@ public class QuestionPoolTest extends Deployments { .assertStandardDeviation(0.3d) .assertDiscriminationIndex(-0.7d) .assertDistractors(2) - .assertUsage(3); + .assertUsage(3) + .assertCorrectionTime(5); } } diff --git a/src/test/java/org/olat/selenium/page/qpool/QuestionMetadataPage.java b/src/test/java/org/olat/selenium/page/qpool/QuestionMetadataPage.java index 48831ae9ef3003f6ab90f677d6187f51db99fe06..77f6aa86fd39625b326fe9cb7dc261e09bee62fd 100644 --- a/src/test/java/org/olat/selenium/page/qpool/QuestionMetadataPage.java +++ b/src/test/java/org/olat/selenium/page/qpool/QuestionMetadataPage.java @@ -136,11 +136,12 @@ public class QuestionMetadataPage { * @param standardDeviation Value between 0.0 and 1.0 * @param discriminationIndex Value between -1.0 and 1.0 * @param distractors The number of distractors - * @param usage + * @param usage Number of times this questions is used + * @param correctionTime Time in minutes to correction the question * @return Itself */ public QuestionMetadataPage setItemAnalyse(Double difficulty, Double standardDeviation, - Double discriminationIndex, Integer distractors, Integer usage) { + Double discriminationIndex, Integer distractors, Integer usage, Integer correctionTime) { if(difficulty != null) { By difficultyBy = By.cssSelector(".o_sel_qpool_metadata_item_analyse .o_sel_difficulty input[type='text']"); @@ -166,6 +167,10 @@ public class QuestionMetadataPage { usageEl.clear(); usageEl.sendKeys(usage.toString()); } + if(correctionTime != null) { + By correctionTimeBy = By.cssSelector(".o_sel_qpool_metadata_item_analyse .o_sel_correction_time input[type='text']"); + browser.findElement(correctionTimeBy).sendKeys(correctionTime.toString()); + } return this; } @@ -261,6 +266,12 @@ public class QuestionMetadataPage { return this; } + public QuestionMetadataPage assertCorrectionTime(Integer timeInMinutes) { + By correctionTimeBy = By.xpath("//div[contains(@class,'o_sel_correction_time')]//input[@value='" + timeInMinutes + "']"); + OOGraphene.waitElement(correctionTimeBy, browser); + return this; + } + public QuestionMetadataPage saveGeneralMetadata() { return saveMetadata("o_sel_qpool_metadata_general"); } diff --git a/src/test/resources/arquillian.xml b/src/test/resources/arquillian.xml index e0a73610f545446d425acf5c025431413d1096c6..d710391bc9bc8a1160481c3d664b69f6b270dbba 100644 --- a/src/test/resources/arquillian.xml +++ b/src/test/resources/arquillian.xml @@ -25,7 +25,7 @@ <property name="dimensions">1024x800</property> <!-- <property name="downloadBinaries">no</property> - <property name="chromeDriverBinary">target/drone/12b3858a57bfe0a3d450cd194e0992aa/chromedriver</property> + <property name="chromeDriverBinary">target/drone/57d2a9629298aa6dc2d759fe09da5d13/chromedriver</property> <property name="firefoxDriverBinary">target/drone/ce03addb1fc8c24900011f90fc80f3c1/geckodriver</property> --> <property name="firefoxUserPreferences">src/test/profile/firefox/prefs.js</property>