From eae00a6d75ddac64bef53bfc3e6fd0625af0694a Mon Sep 17 00:00:00 2001 From: srosse <stephane.rosse@frentix.com> Date: Tue, 7 Jan 2020 19:41:43 +0100 Subject: [PATCH] OO-4438: add correction time to question's metadata --- pom.xml | 2 +- .../java/org/olat/core/util/FileUtils.java | 48 +++---- .../ims/qti/qpool/QTIImportProcessor.java | 136 ++++++------------ .../ims/qti/qpool/QTIMetadataConverter.java | 18 ++- .../model/xml/AssessmentItemMetadata.java | 13 ++ .../ims/qti21/model/xml/ManifestBuilder.java | 18 +-- .../model/xml/ManifestMetadataBuilder.java | 5 + .../ims/qti21/pool/QTI21ImportProcessor.java | 11 +- .../olat/modules/qpool/QuestionItemShort.java | 3 + .../qpool/manager/QuestionItemDAO.java | 3 + .../manager/QuestionItemDocumentFactory.java | 4 +- .../olat/modules/qpool/model/ItemWrapper.java | 28 ++-- .../modules/qpool/model/QuestionItemImpl.java | 13 ++ .../qpool/ui/AbstractItemListController.java | 1 + .../org/olat/modules/qpool/ui/ItemRow.java | 5 + .../qpool/ui/QuestionItemAuditLogExport.java | 7 +- .../qpool/ui/QuestionItemDataModel.java | 4 +- .../qpool/ui/_i18n/LocalStrings_de.properties | 2 + .../qpool/ui/_i18n/LocalStrings_en.properties | 2 + .../QuestionMetadataEditController.java | 15 +- .../database/mysql/alter_14_1_x_to_14_2_0.sql | 4 + .../database/mysql/setupDatabase.sql | 1 + .../oracle/alter_14_1_x_to_14_2_0.sql | 2 + .../database/oracle/setupDatabase.sql | 1 + .../postgresql/alter_14_1_x_to_14_2_0.sql | 4 + .../database/postgresql/setupDatabase.sql | 1 + .../ims/qti/qpool/QTIExportProcessorTest.java | 7 +- .../ims/qti/qpool/QTIImportProcessorTest.java | 59 +++++--- .../olat/ims/qti/qpool/qitem_metadatas.zip | Bin 1758 -> 3128 bytes .../QTIStatisticsManagerLargeTest.java | 33 +++-- .../qpool/manager/QuestionDAOTest.java | 2 + .../org/olat/selenium/QuestionPoolTest.java | 5 +- .../page/qpool/QuestionMetadataPage.java | 15 +- src/test/resources/arquillian.xml | 2 +- 34 files changed, 271 insertions(+), 203 deletions(-) diff --git a/pom.xml b/pom.xml index 0ccba6f8b19..2cf4175b96f 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 58cba9304f2..414630b439b 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 c45f7c354a0..1365a3cbc6e 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 df8de04cf14..8f3e15fe2a8 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 1d2ca535ee4..b9d8717e048 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 16aee5afb77..4fea39e6353 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 a48fbb2703c..fbd7fd9fe19 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 f872dbe7df9..c857c026064 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 6dc3d547885..6361e0067dc 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 71cab0a872b..5b3d2922c2c 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 951961ba9f0..3d227a77779 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 9c76e320ec4..a75173196ae 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 f7976aeeb9d..94e8d2703c4 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 9aa36b2a0b1..cf3afdf59bb 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 3db090a14cb..87fb4778c9f 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 670914e8fac..03221bf71e8 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 d35e2c50d24..a6517ec1580 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 93a2c38898d..255f4dcfb9f 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 1045cc6a1e7..5530355799b 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 cc6c8b0a1a5..b971e57d03c 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 544d7b50c7a..6de790bfa5b 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 914261fb98a..7c05dd24ad5 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 8c5828838bb..cd0b42f81b4 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 0860673c063..cdcce51147a 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 50f3fff6f9b..59e40c347e7 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 e4f9d3225ed..63905caeb91 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 60d87d43071..c9ed1afbbb4 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 d4339eae321..3cc94892b75 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 GIT binary patch literal 3128 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 delta 1618 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 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 6843608d41a..b0431c92b1c 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 c6ec572b6b5..baf4251e78d 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 d190bff7867..5229f2cbece 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 48831ae9ef3..77f6aa86fd3 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 e0a73610f54..d710391bc9b 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> -- GitLab