/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de * <p> */ package org.olat.course.nodes.iq; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; import org.apache.velocity.VelocityContext; import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; import org.olat.core.gui.components.velocity.VelocityContainer; 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.gui.control.generic.wizard.WizardController; import org.olat.core.helpers.Settings; import org.olat.core.id.Identity; import org.olat.core.logging.OLATRuntimeException; import org.olat.core.util.mail.MailBundle; import org.olat.core.util.mail.MailContext; import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailManager; import org.olat.core.util.mail.MailNotificationEditController; import org.olat.core.util.mail.MailTemplate; import org.olat.core.util.mail.MailerResult; import org.olat.course.CourseFactory; import org.olat.course.ICourse; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.IQSELFCourseNode; import org.olat.course.nodes.IQSURVCourseNode; import org.olat.course.nodes.IQTESTCourseNode; import org.olat.fileresource.DownloadeableMediaResource; import org.olat.ims.qti.QTIResult; import org.olat.ims.qti.QTIResultManager; import org.olat.ims.qti.QTIResultSet; import org.olat.ims.qti.editor.beecom.parser.ItemParser; import org.olat.ims.qti.export.QTIExportEssayItemFormatConfig; import org.olat.ims.qti.export.QTIExportFIBItemFormatConfig; import org.olat.ims.qti.export.QTIExportFormatter; import org.olat.ims.qti.export.QTIExportFormatterCSVType1; import org.olat.ims.qti.export.QTIExportFormatterCSVType3; import org.olat.ims.qti.export.QTIExportItemFormatConfig; import org.olat.ims.qti.export.QTIExportKPRIMItemFormatConfig; import org.olat.ims.qti.export.QTIExportMCQItemFormatConfig; import org.olat.ims.qti.export.QTIExportManager; import org.olat.ims.qti.export.QTIExportSCQItemFormatConfig; import org.olat.ims.qti.export.helper.QTIItemObject; import org.olat.ims.qti.export.helper.QTIObjectTreeBuilder; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; import org.olat.repository.controllers.ReferencableEntriesSearchController; import org.olat.user.UserManager; import de.bps.onyx.plugin.OnyxExportManager; /** * * Description:<br> * Wizard for replacement of an already linked test * * <P> * Initial Date: 21.10.2008 <br> * @author skoeber * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ public class IQEditReplaceWizard extends WizardController { /** three steps: information + export results, search, mail */ private static final int STEPS = 3; //needed objects private String resultExportFile; private File exportDir; private ICourse course; private CourseNode courseNode; private RepositoryEntry selectedRepositoryEntry; private List<Identity> learners; private List<QTIResult> results; private String[] types; private boolean isOnyx; // presentation private VelocityContainer vcStep1, vcStep2, vcStep3; private Link nextBtn, showFileButton; private MailNotificationEditController mailCtr; private ReferencableEntriesSearchController searchCtr; private MailManager mailManager; /** * a number of identities with qti.ser entry */ private int numberOfQtiSerEntries; /** * Standard constructor * @param ureq * @param wControl * @param course * @param courseNode */ public IQEditReplaceWizard(UserRequest ureq, WindowControl wControl, ICourse course, CourseNode courseNode, String[] types, List<Identity> learners, List<QTIResult> results, int numberOfQtiSerEntries, boolean isOnyx) { super(ureq, wControl, STEPS); setBasePackage(IQEditReplaceWizard.class); mailManager = CoreSpringFactory.getImpl(MailManager.class); this.course = course; this.courseNode = courseNode; this.types = types; this.learners = learners; this.results = results; this.numberOfQtiSerEntries = numberOfQtiSerEntries; this.isOnyx = isOnyx; setWizardTitle(translate("replace.wizard.title")); doStep1(ureq); } @Override public void event(UserRequest ureq, Component source, Event event) { if(source == nextBtn) { doStep3(ureq); } else if(source == showFileButton) { ureq.getDispatchResult().setResultingMediaResource(new DownloadeableMediaResource(new File(exportDir, resultExportFile))); } else if(event.getCommand().equals("cmd.wizard.cancel")) { fireEvent(ureq, Event.CANCELLED_EVENT); } } @Override protected void event(UserRequest ureq, Controller source, Event event) { if(source == mailCtr && event == Event.DONE_EVENT) { MailTemplate mailTemplate = mailCtr.getMailTemplate(); if(mailTemplate != null) { MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString()); String metaId = UUID.randomUUID().toString().replace("-", ""); MailerResult result = new MailerResult(); MailBundle[] bundles = mailManager.makeMailBundles(context, learners, mailTemplate, getIdentity(), metaId, result); result.append(mailManager.sendMessage(bundles)); if(mailTemplate.getCpfrom()) { MailBundle ccBundle = mailManager.makeMailBundle(context, getIdentity(), mailTemplate, getIdentity(), metaId, result); result.append(mailManager.sendMessage(ccBundle)); } } fireEvent(ureq, Event.DONE_EVENT); } else if (source == searchCtr && event == ReferencableEntriesSearchController.EVENT_REPOSITORY_ENTRY_SELECTED) { selectedRepositoryEntry = searchCtr.getSelectedEntry(); if (isOnyx) { doStep2Onyx(ureq); } else { doStep2(ureq); } } } private void doStep1(UserRequest ureq) { searchCtr = new ReferencableEntriesSearchController(getWindowControl(), ureq, types, translate("command.chooseTest")); searchCtr.addControllerListener(this); vcStep1 = createVelocityContainer("replacewizard_step1"); vcStep1.put("search", searchCtr.getInitialComponent()); setNextWizardStep(translate("replace.wizard.title.step1"), vcStep1); } private void doStep2(UserRequest ureq) { String nodeTitle = courseNode.getShortTitle(); if (results != null && results.size() > 0) { exportDir = CourseFactory.getOrCreateDataExportDirectory(ureq.getIdentity(), course.getCourseTitle()); UserManager um = UserManager.getInstance(); String charset = um.getUserCharset(ureq.getIdentity()); QTIExportManager qem = QTIExportManager.getInstance(); Long repositoryRef = results.get(0).getResultSet().getRepositoryRef(); List<QTIItemObject> qtiItemObjectList = new QTIObjectTreeBuilder().getQTIItemObjectList(repositoryRef); QTIExportFormatter formatter; if (courseNode instanceof IQTESTCourseNode) { formatter = new QTIExportFormatterCSVType1(ureq.getLocale(), "\t", "\"", "\r\n", false); } else if (courseNode instanceof IQSELFCourseNode) { formatter = new QTIExportFormatterCSVType1(ureq.getLocale(),"\t", "\"", "\r\n", false); ((QTIExportFormatterCSVType1)formatter).setAnonymous(true); } else { formatter = new QTIExportFormatterCSVType3(ureq.getLocale(), null, "\t", "\"", "\r\n", false); } Map<Class<?>, QTIExportItemFormatConfig> qtiItemConfigs = getQTIItemConfigs(qtiItemObjectList); formatter.setMapWithExportItemConfigs(qtiItemConfigs); resultExportFile = qem.exportResults(formatter, results, qtiItemObjectList, courseNode.getShortTitle(), exportDir, charset, ".xls"); vcStep2 = createVelocityContainer("replacewizard_step2"); String[] args1 = new String[] { Integer.toString(learners.size()) }; vcStep2.contextPut("information", translate("replace.wizard.information.paragraph1", args1)); String[] args2 = new String[] { exportDir.getName(), resultExportFile }; vcStep2.contextPut("information_par2", translate("replace.wizard.information.paragraph2", args2)); vcStep2.contextPut("nodetitle", nodeTitle); showFileButton = LinkFactory.createButton("replace.wizard.showfile", vcStep2, this); } else { // it exists no result String[] args = new String[] { Integer.toString(numberOfQtiSerEntries) }; vcStep2 = createVelocityContainer("replacewizard_step2"); vcStep2.contextPut("information", translate("replace.wizard.information.empty.results", args)); vcStep2.contextPut("nodetitle", nodeTitle); } nextBtn = LinkFactory.createButton("replace.wizard.next", vcStep2, this); setNextWizardStep(translate("replace.wizard.title.step2"), vcStep2); } /** * Does export of test results for onyx tests * @param ureq */ private void doStep2Onyx(UserRequest ureq) { String nodeTitle = courseNode.getShortTitle(); exportDir = CourseFactory.getOrCreateDataExportDirectory(ureq.getIdentity(), course.getCourseTitle()); OnyxExportManager onyxExportManager = OnyxExportManager.getInstance(); if (courseNode.getClass().equals(IQSURVCourseNode.class)) { // it is an onyx survey String surveyPath = course.getCourseEnvironment().getCourseBaseContainer().getBasefile() + File.separator + courseNode.getIdent() + File.separator; resultExportFile = onyxExportManager.exportResults(surveyPath, exportDir, courseNode); } else { String repositorySoftKey = (String) courseNode.getModuleConfiguration().get(IQEditController.CONFIG_KEY_REPOSITORY_SOFTKEY); Long repKey = RepositoryManager.getInstance().lookupRepositoryEntryBySoftkey(repositorySoftKey, true).getKey(); QTIResultManager qrm = QTIResultManager.getInstance(); List<QTIResultSet> resultSets = qrm.getResultSets(course.getResourceableId(), courseNode.getIdent(), repKey, null); learners = new ArrayList<Identity>(); for (QTIResultSet resultSet : resultSets) { if (!learners.contains(resultSet.getIdentity())) { learners.add(resultSet.getIdentity()); } } resultExportFile = onyxExportManager.exportResults(resultSets, exportDir, courseNode); } // vcStep2 = new VelocityContainer("replaceWizard", VELOCITY_ROOT + "/replacewizard_step2.html", translator, this); vcStep2 = createVelocityContainer("replacewizard_step2"); String[] args = new String[] {Integer.toString(learners != null ? learners.size() : 0), exportDir.getName(), resultExportFile }; vcStep2.contextPut("information", getTranslator().translate("replace.wizard.information", args)); vcStep2.contextPut("nodetitle", nodeTitle); vcStep2.contextPut("filename", resultExportFile); showFileButton = LinkFactory.createButton("replace.wizard.showfile", vcStep2, this); nextBtn = LinkFactory.createButton("replace.wizard.next", vcStep2, this); this.setNextWizardStep(getTranslator().translate("replace.wizard.title.step2"), vcStep2); } private void doStep3(UserRequest ureq) { StringBuilder extLink = new StringBuilder(); extLink.append(Settings.getServerContextPathURI()); RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(course, true); extLink.append("/url/RepositoryEntry/").append(re.getKey()); extLink.append("/CourseNode/").append(courseNode.getIdent()); String[] bodyArgs = new String[] { course.getCourseTitle(), extLink.toString() }; String subject = translate("inform.users.subject", bodyArgs); String body = translate("inform.users.body", bodyArgs); MailTemplate mailTempl = new MailTemplate(subject, body, null) { @Override public void putVariablesInMailContext(VelocityContext context, Identity identity) { // nothing to do } }; removeAsListenerAndDispose(mailCtr); mailCtr = new MailNotificationEditController(getWindowControl(), ureq, mailTempl, false, false, true); listenTo(mailCtr); vcStep3 = createVelocityContainer("replacewizard_step3"); vcStep3.put("mailform", mailCtr.getInitialComponent()); setNextWizardStep(translate("replace.wizard.title.step3"), vcStep3); } /** * @return the selected RepositoryEntry */ protected RepositoryEntry getSelectedRepositoryEntry() { return selectedRepositoryEntry; } private Map<Class<?>, QTIExportItemFormatConfig> getQTIItemConfigs(List<QTIItemObject> qtiItemObjectList){ Map<Class<?>, QTIExportItemFormatConfig> itConfigs = new HashMap<Class<?>, QTIExportItemFormatConfig>(); for (Iterator<QTIItemObject> iter = qtiItemObjectList.iterator(); iter.hasNext();) { QTIItemObject item = iter.next(); if (item.getItemIdent().startsWith(ItemParser.ITEM_PREFIX_SCQ)){ if (itConfigs.get(QTIExportSCQItemFormatConfig.class) == null){ QTIExportSCQItemFormatConfig confSCQ = new QTIExportSCQItemFormatConfig(true, false, false, false); itConfigs.put(QTIExportSCQItemFormatConfig.class, confSCQ); } } else if (item.getItemIdent().startsWith(ItemParser.ITEM_PREFIX_MCQ)){ if (itConfigs.get(QTIExportMCQItemFormatConfig.class) == null){ QTIExportMCQItemFormatConfig confMCQ = new QTIExportMCQItemFormatConfig(true, false, false, false); itConfigs.put(QTIExportMCQItemFormatConfig.class, confMCQ ); } } else if (item.getItemIdent().startsWith(ItemParser.ITEM_PREFIX_KPRIM)){ if (itConfigs.get(QTIExportKPRIMItemFormatConfig.class) == null){ QTIExportKPRIMItemFormatConfig confKPRIM = new QTIExportKPRIMItemFormatConfig(true, false, false, false); itConfigs.put(QTIExportKPRIMItemFormatConfig.class, confKPRIM); } } else if (item.getItemIdent().startsWith(ItemParser.ITEM_PREFIX_ESSAY)){ if (itConfigs.get(QTIExportEssayItemFormatConfig.class) == null){ QTIExportEssayItemFormatConfig confEssay = new QTIExportEssayItemFormatConfig(true, false); itConfigs.put(QTIExportEssayItemFormatConfig.class, confEssay); } } else if (item.getItemIdent().startsWith(ItemParser.ITEM_PREFIX_FIB)){ if (itConfigs.get(QTIExportFIBItemFormatConfig.class) == null){ QTIExportFIBItemFormatConfig confFIB = new QTIExportFIBItemFormatConfig(true, false, false); itConfigs.put(QTIExportFIBItemFormatConfig.class, confFIB); } } else if (item.getItemType().equals(QTIItemObject.TYPE.A)){ QTIExportEssayItemFormatConfig confEssay = new QTIExportEssayItemFormatConfig(true, false); itConfigs.put(QTIExportEssayItemFormatConfig.class, confEssay); } else if (item.getItemType().equals(QTIItemObject.TYPE.R)){ QTIExportSCQItemFormatConfig confSCQ = new QTIExportSCQItemFormatConfig(true, false, false, false); itConfigs.put(QTIExportSCQItemFormatConfig.class, confSCQ); } else if (item.getItemType().equals(QTIItemObject.TYPE.C)){ QTIExportMCQItemFormatConfig confMCQ = new QTIExportMCQItemFormatConfig(true, false, false, false); itConfigs.put(QTIExportMCQItemFormatConfig.class, confMCQ ); } else if (item.getItemType().equals(QTIItemObject.TYPE.B)){ QTIExportFIBItemFormatConfig confFIB = new QTIExportFIBItemFormatConfig(true, false, false); itConfigs.put(QTIExportFIBItemFormatConfig.class, confFIB); } else{ throw new OLATRuntimeException(null,"Can not resolve QTIItem type", null); } } return itConfigs; } }